Skip to content

入门

https://cn.vuejs.org/

轻量级的前端界面框架
2016.10 发布最新 2.0 版本,更强大,更快速

数据渲染/数据同步
组件化/模块化 其他功能:路由、ajax,数据流

Vue实例

每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的:

1
2
3
4
5
6
new Vue({ 
    el: '#app',
    data: {
        message: 'Hello Vue.js!'
    }
})
1
2
3
4
5
6
7
var my = new Vue({ 
    el: '#app',
    template: '<div>{{ fruit }}</div>',
    data: {
        fruit: 'apple',
    }
})
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<div id="app"></div>
<script type="text/javascript">
new Vue({
    el: '#app',
    template: "<p>hello world --- {{ word }} </p>",
    data: {
        word: 'data content'
    }
})
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Page Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        {{ message }}
    </div>

    <script type="text/javascript">
    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        }
    })
    </script>

</body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Vue 入门</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="root">{{ msg }}</div>
    <script>
    new Vue({ // 创建一个实例
        el: "#root", // 接管 id=root 的内容,与 id 为 root 的 DOM 做绑定
        data: { // 实例中的数据
            msg: "hello world"
        }
    })
    </script>
</body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<div id="app">{{ content }}</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            content: 'hello world'
        }
    })
    setTimeout(function() {
        vm.$data.content = 'bye world'
    }, 2000)
</script>

MVVM 模式

MVP 模式:
Model(数据层,封装了核心数据和逻辑功能的模型)
View(视图层,负责显示)
Presenter(封装了视图的所有操作和响应用户的输入、输出和事件等,View 并不直接使用 Model,它们之间的通信是通过 Presenter 来进行的,所有的交互都发生在 Presenter 内部)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>TodoList Jquery</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</head>
<body>
    <!-- 视图层 -->
    <div>
        <input id="input" type="text">
        <button id="btn">提交</button>
        <ul id="list"></ul>
    </div>
    <script>
        function Page() {

        }
        // Presenter 控制器 视图和模型的中转站
        // 基本上都是在做 DOM 操作
        $.extend(Page.prototype, {
            init: function() {
                this.bindEvents()
            },
            bindEvents: function() {
                var btn = $('#btn');
                btn.on('click', $.proxy(this.handleBtnClick, this))
            },
            handleBtnClick: function() {
                var inputElem = $("#input");
                var inputValue = $("#input").val();
                var ulElem = $("#list");
                ulElem.append('<li>' + inputValue + '</li>');
                inputElem.val('');
            }
        })
        var page = new Page();
        page.init();
    </script>
</body>
</html>

MVVM

ViewModel 是 Vue 内置的,只要关注 View 和 Model 就可以了

注意力主要放在 Model 层,面向数据编程(MVP 主要面向 DOM 操作)

MVVM 模式和 MVC 模式一样,主要目的是分离视图(View)和模型(Model)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- View 层 -->
<div id="app">
    <input type="text" v-model="inputValue">
    <button v-on:click="handleBtnClick">提交</button>
    <ul>
        <li v-for="item in list">{{ item }}</li>
    </ul>
</div>
<script>
    // Model 层
    var app = new Vue({
        el: "#app",
        data: {
            list: [],
            inputValue: ''
        },
        methods: {
            handleBtnClick: function() {
                this.list.push(this.inputValue)
                this.inputValue = ''
            }
        }
    })
</script>

挂载点、模板、实例之间的关系

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Vue 入门</title>
    <script src="./vue.js"></script>
</head>
<body>
    <!-- Vue 实例的挂载点 -->
    <div id="root">
        <!-- 挂载点内部的内容称为模板 -->
    </div> 

    <script>
    new Vue({ // 创建一个实例
        el: "#root", // 接管 id=root 的内容,与 id 为 root 的 DOM 做绑定
        template: '<h1>hello {{ msg }}</h1> ',
        data: { // 实例中的数据
            msg: " world"
        }
    })
    </script>
</body>
</html>

数据、事件和方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<div id="root">
    <!-- 插值表达式 -->
    <h1> {{ number }}</h1>
    <h1 v-text="number"></h1>
    <h1 v-html="number"></h1>
    <h1 v-text="content"></h1>
    <h1 v-html="content"></h1>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        msg: " world",
        number: 123,
        content: '<h1>hello</h1>'
    }
})
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<div id="root">
    <div v-on:click="handleClick"> {{ content }}</div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        content: 'hello'
    },
    methods: {
        handleClick: function() {
            alert(123);
        }
    }
})
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<div id="root">
    <div v-on:click="handleClick"> {{ content }}</div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        content: 'hello'
    },
    methods: {
        handleClick: function() {
            this.content = "world"
        }
    }
})
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<div id="root">
    <!-- 使用 @ 绑定 -->
    <div @click="handleClick"> {{ content }}</div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        content: 'hello'
    },
    methods: {
        handleClick: function() {
            this.content = "world"
        }
    }
})

属性绑定和双向绑定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<div id="root">
    <div v-bind:title="'nocliantro ' + title">hello world</div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        title: "this is hello world"
    }
})
</script>

使用冒号 : 代替 v-bind:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<div id="root">
    <div :title="'nocliantro ' + title">hello world</div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        title: "this is hello world"
    }
})
</script>

双向绑定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<div id="root">
        <div :title="title">hello world</div>
        <input v-model="content">
        <div> {{ content }} </div>
    </div> 
    <script>
    new Vue({ 
        el: "#root", 
        data: {
            title: "this is hello world",
            content: 'this is content'
        }
    })
    </script>

计算属性和侦听器

计算属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<div id="root">
    姓:<input v-model='firstName'>
    名:<input v-model='lastName'>
    <div> {{ fulltName }} </div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        firstName: '',
        lastName: ''
    },
    computed: {
        fulltName: function() {
            return this.firstName + ' ' + this.lastName;
        }
    }
})
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div id="root">
    姓:<input v-model='firstName'>
    名:<input v-model='lastName'>
    <div> {{ fulltName }} </div>
    <div> {{ count }} </div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        firstName: '',
        lastName: '',
        count: 0,
    },
    computed: {
        fulltName: function() {
            return this.firstName + ' ' + this.lastName;
        }
    },
    watch: {
        firstName: function() {
            this.count++;
        },
        lastName: function() {
            this.count++;
        }
    }
})

侦听计算属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div id="root">
    姓:<input v-model='firstName'>
    名:<input v-model='lastName'>
    <div> {{ fulltName }} </div>
    <div> {{ count }} </div>
</div> 
<script>
new Vue({ 
    el: "#root", 
    data: {
        firstName: '',
        lastName: '',
        count: 0,
    },
    computed: {
        fulltName: function() {
            return this.firstName + ' ' + this.lastName;
        }
    },
    watch: {
        fulltName: function() {
            this.count++;
        },
    }
})
</script>

v-if,v-show与v-for

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<div id="root">
    <div v-if="show">hello world</div>
    <button @click="handleClick">toggle</button>
</div>
<script>
    new Vue({
        el: "#root",
        data: {
            show: true
        },
        methods: {
            handleClick: function() {
                this.show = !this.show
            }
        }
    })
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<div id="root">
    <div v-show="show">hello world</div>
    <button @click="handleClick">toggle</button>
</div>
<script>
    new Vue({
        el: "#root",
        data: {
            show: true
        },
        methods: {
            handleClick: function() {
                this.show = !this.show
            }
        }
    })
</script>

v-if 如果为 false,会直接移除相应标签,v-show 为 false 会设置显示为 none,v-show 一般会效率高一些

v-for 加 key 值可以提升性能,要求 key 值不能相同

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="root">
    <div v-show="show">hello world</div>
    <button @click="handleClick">toggle</button>
    <ul>
        <li v-for="(item, index) of list" :key="index">{{ item }}</li>
    </ul>
</div>
<script>
    new Vue({
        el: "#root",
        data: {
            show: true,
            list: [1, 2, 3]
        },
        methods: {
            handleClick: function() {
                this.show = !this.show
            }
        }
    })
</script>

组件

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:

在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例

组件就是页面上的一块区域

使用组件代码维护起来比较方便

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Page Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="example">
        <my-component></my-component>
    </div>

    <script type="text/javascript">

    // 定义
    var MyComponent = Vue.extend({
        template: '<div>A custom component!</div>'
    })

    // 注册
    Vue.component('my-component', MyComponent)

    // 创建根实例
    new Vue({
        el: '#example'
    })
    </script>

</body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<div id="app">
    hello
    <my-header></my-header>
</div>
<script type="text/javascript">
Vue.component('my-header', {
    template: '<p>this is my header</p>'
})
new Vue({
    el: '#app',
    data: {
        word: 'data content'
    }
})
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<div id="app">
    hello
    <my-header2></my-header2>
</div>
<script type="text/javascript">
var myHeader = Vue.component('my-header', {
    template: '<h1>this is my header</h1>'
})
new Vue({
    el: '#app',
    data: {
        word: 'data content'
    },
    components: {
        'my-header2': myHeader
    }
})
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
    hello
    <my-header></my-header>
</div>
<script type="text/javascript">
var myHeaderChild = Vue.component('my-header', {
    template: '<p>I am my header child</p>',
})
var myHeader = Vue.component('my-header', {
    template: '<p>this is my header <my-header-child></my-header-child></p>',
    components: {
        'my-header-child': myHeaderChild
    }
})
new Vue({
    el: '#app',
    data: {
        word: 'data content'
    },
    components: {
        'my-header': myHeader
    }
})
</script>

制作一个极简todolist

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div id="root">
    <div>
        <input v-model="inputValue">
        <button @click="handleSubmit">提交</button>
    </div>
    <ul>
        <li v-for="(item, index) of list" :key="index">
            {{ item }}
        </li>
    </ul>
</div>
<script>
    new Vue({
        el: "#root",
        data: {
            inputValue: '',
            list: []
        },
        methods: {
            handleSubmit: function() {
                this.list.push(this.inputValue)
                this.inputValue = ''
            }
        }
    })
</script>

组件的拆分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<div id="root">
    <div>
        <input v-model="inputValue">
        <button @click="handleSubmit">提交</button>
    </div>
    <ul>
        <todo-item 
            v-for="(item, index) of list"
            :key="index"
            :content="item"
            >
        </todo-item>
    </ul>
</div>
<script>
    Vue.component('todo-item', {
        props: ['content'],
        template: '<li> {{ content }} </li>',
    })
    new Vue({
        el: "#root",
        data: {
            inputValue: '',
            list: []
        },
        methods: {
            handleSubmit: function() {
                this.list.push(this.inputValue)
                this.inputValue = ''
            }
        }
    })
</script>

每一个组件都是一个实例

删除功能

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<div id="root">
    <div>
        <input v-model="inputValue">
        <button @click="handleSubmit">提交</button>
    </div>
    <ul>
        <todo-item 
            v-for="(item, index) of list"
            :key="index"
            :content="item"
            :index="index"
            @delete="handleDelete"
            >
        </todo-item>
    </ul>
</div>
<script>
    Vue.component('todo-item', {
        props: ['content', 'index'],
        template: '<li @click="handleClick"> {{ content }} {{ index }} </li>',
        methods: {
            handleClick: function() {
                this.$emit('delete', this.index)
            }
        }
    })
    new Vue({
        el: "#root",
        data: {
            inputValue: '',
            list: []
        },
        methods: {
            handleSubmit: function() {
                this.list.push(this.inputValue)
                this.inputValue = ''
            },
            handleDelete: function(index) {
                this.list.splice(index, 1)
            }
        }
    })
</script>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Todolist</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <input type="text" v-model="inputValue">
        <button @click="handleBtnClick">提交</button>
        <ul>
            <!-- <li v-for="item in list">{{ item }}</li> -->
            <todo-item :content="item" 
                       :index="index"
                       v-for="(item, index) in list"
                       @delete="handleItemDelete">
            </todo-item>
        </ul>
    </div>
    <script>
        // Vue.component("TodoItem", {
        //     props: ['content'],
        //     template: "<li>{{ content }}</li>"
        // })
        var TodoItem = {
            props: ['content', 'index'],
            template: "<li @click='handleItemClick'>{{ content }}</li>",
            methods: {
                handleItemClick: function() {
                    this.$emit("delete", this.index);
                }
            }
        }
        var app = new Vue({
            el: "#app",
            components: {
                TodoItem: TodoItem,
            },
            data: {
                list: [],
                inputValue: ''
            },
            methods: {
                handleBtnClick: function() {
                    this.list.push(this.inputValue)
                    this.inputValue = ''
                },
                handleItemDelete: function(index) {
                    this.list.splice(index, 1)
                }
            }
        })
    </script>
</body>
</html>