0%

Vue基础

基本案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
<div id="app">
<h1>hello {{ msg }}</h1>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
vm = new Vue({
el: '#app', // 创建实例和对应的Dom进行绑定
data: {
msg: "hello vue!"
}
})
</script>

Vue不同于直接使用js,js操作的对象是dom对象,而Vue则操作的是数据对象,因为都是将数据和dom进行绑定的,而我们想要改变值,直接通过改变数据即可。

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

id为app的div标签就是vue实例的挂载点,vue只会处理对应挂载点下的内容。在挂载点内部的内容都叫做模板,像上面的ID为app的div内的h1标签就是模板。

1
2
3
4
5
6
7
8
9
10
11
12
<!--除了在挂载点内手写模板之外,还可以采用在vue实例内部定义模板的方式-->
<div id="app"></div>
<script type="application/javascript">
vm = new Vue({
el: '#app',
// 在vue实例内部使用template定义模板
template: '<h1>hello {{ msg }}</h1>',
data: {
msg: "vue!"
}
})
</script>

所以模板可以写在挂载点内部,也可以写在vue实例内,使用template定义

注意使用template时,会将挂载点内的内容进行覆盖

指令

均采用 v- 开头

  • v-text=‘data中的数据’:将标签内的显示内容同实例中的data中的值联系
  • v-html=‘data中的数据’:作用和v-text一致,但是若data中的内容为html代码,则会渲染到页面,即不会对html代码进行转义
  • v-on:绑定事件监听器,简写形式:@
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <div id="app">
    <!--绑定点击事件,绑定函数名,无参数的函数可以直接写函数名即可,两者的效果是一样的-->
    <div v-on:click="handleClick">{{content}}</div>
    <div @click="handleClick">{{content}}</div>
    </div>
    <script type="application/javascript">
    vm = new Vue({
    el: '#app',
    data: {
    msg: "vue!",
    content: 'hello'
    },
    methods: { // 需要调用的方法在methods中进行定义,但是要注意函数不能使用箭头函数
    handleClick: function(){
    // 函数中的this指定的当前的vue实例对象
    this.content = this.msg
    }
    }
    })
    </script>

注意:不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch(‘a’, newValue => this.myMethod())。因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。

属性绑定和双向绑定

使用v-bind将某个标签属性和vue实例的data属性绑定,v-bind可以直接简写成 ,使用冒号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
<div id="app">
<div v-bind:title=" 'woshi:'+ title">hello</div>
<div :title=" 'woshi:'+ title">hello</div>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
vm = new Vue({
el: '#app',
data: {
title: "this is hello vue"
}
})
</script>

<div v-bind:title=" 'woshi:'+ title">hello</div> 绑定之后,是可以直接写js表达式的。

双向数据绑定:使用v-model模板指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>
<div id="app">
<div v-bind:title="'woshi '+ title">hello</div>
<!--使用v-model进行双向的数据绑定-->
<input v-model="content"/>
<div>{{content}}</div>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
vm = new Vue({
el: '#app',
data: {
title: "this is hello vue",
content: "hello"
}
})
</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
<body>
<div id="app">
姓:<input v-model="firstName"/>
名:<input v-model="lastName"/>
<div>{{fullName}}</div> <!--计算属性也是属性,调用方式是一样的-->
<div>{{count}}</div>

</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName:'',
count: 0,
},
computed: { // 定义计算属性,根据其他的数据项计算出的结果,其他数据未发生变化的时候不去调用,会使用缓存
fullName: function () {
return this.firstName + this.lastName
}
},
watch:{ // 定义侦听器,当侦听的属性发生变化的时候调用
firstName:function(){
this.count++
},
lastName: function(){
this.count++
}
}
})
</script>

使用computed创建一个计算属性(注意:使用计算属性的时候,函数一定要return返回语句),绑定一个函数,计算属性也是属性,调用方式和插值操作一致。使用计算属性的好处是,计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算,所以性能较高。

侦听器:
当侦听的属性发生变化的时候调用,Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。上面的侦听器还可以侦听计算属性

1
2
3
4
5
watch:{ // 定义侦听器,当侦听的属性发生变化的时候调用
funName:function(){
this.count++
}
}

v-if、v-for、v-show

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<body>
<div id="app">
<!-- v-if和v-show的区别在于使用 -->
<div v-show="show">hello world</div>
<div v-if="show">hello world</div>
<button @click="handleClick">button</button>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
vm = new Vue({
el: '#app',
data:{
show: true,
},
methods:{
handleClick: function(){
this.show = !this.show
}
}
})
</script>

v-if和v-show的区别:

  • 使用v-if时,当判断为false时,是将当前dom移除,而使用v-for则是该当前dom添加sytle='display:none'属性来控制显示和隐藏。
  • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

小结:

v-if控制dom的存在与否,v-show控制dom的显示与否(内部实现是通过添加sytle='display:none'属性来控制)

v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。

案例

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
27
28
29
30
<body>
<div id="app">
<div>
<input v-model="inputValue"/>
<button @click="handleSubmit">提交</button>
</div>
<ul>
<li v-for="(item,index) of list" :key="index">{{item}}</li>
</ul>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
vm = new Vue({
el: '#app',
data:{
inputValue: '',
list: [ ]
},
methods:{
handleSubmit: function(){
if (this.inputValue !=''){
this.list.push(this.inputValue)
this.inputValue = '' // 做了双向绑定
}
}
}
})
</script>

组件

组件是可复用的 Vue 实例,且带有一个名字

全局组件: 可以在任何挂载点内的任何位置使用

1
2
3
4
// 使用Vue.component()定义全局组件,可以在挂载的dom内的任何位置通过组件名进行使用
Vue.component('todo-list',{
template: '<li>item</li>'
})

局部组件:绑定好后可以在当前挂载点内使用

1
2
3
4
5
6
7
8
9
10
// 局部组件,需要在Vue实例内通过components属性进行绑定
var TodoItem = {
template: '<li>item</li>'
}
vm = new Vue({
el: '#app',
components:{
'todo-list':TodoItem
},
}

使用全局组件重新实现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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<body>
<div id="app">
<div>
<input v-model="inputValue"/>
<button @click="handleSubmit">提交</button>
</div>
<ul>
<todo-list
v-for="(item, index) of list"
:key="index"
:content="item" // 组件中的props的值在这里进行赋值,此处想通过数据绑定的方式和根组件进行绑定,也可以不是用绑定,此时content的值就是由给的值决定
></todo-list>
</ul>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
// 使用Vue.component()定义全局组件,可以在挂载的dom内的任何位置通过组件名进行使用
Vue.component('todo-list',{
props: ['content'], // 定义从外部接受的属性
template: '<li>{{content}}</li>'
})

vm = new Vue({
el: '#app',
data:{
inputValue: '',
list: [ ]
},
methods:{
handleSubmit: function(){
if (this.inputValue !=''){
this.list.push(this.inputValue)
this.inputValue = '' // 做了双向绑定
}
}
}
})
</script>

在组件内,想要给template中的代码添加插值,需要在组件的props属性中添加对应的插值变量,在使用组件的时候,对插值变量进行赋值,赋值的方式有两种,第一是可以直接赋值,使用变量=的方式,如content='hello',则所有的插值都是hello,也可以使用对象绑定v-bind:content='vue实例的data中的值'进行数据绑定。

注意:props接受的类型是插值变量的列表形式,只有在进行组件校验的时候才使用字典类型,如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Vue.component('child',{
props:{
content: {
type: [String, Number],
required: true, // 表示是否必须传递
default: 'default value',
validator: function (value){
// 设置相关校验
return (value.length > 5)
}
}
},
template: '<div>{{ content }}</div>'
})

其余时刻都是使用的插值列表的形式。

实现Tolist的删除功能

父组件通过绑定属性的方式向子组件传值,而子组件想改变父组件的值的时候可以通过发布事件的方式。

组件模板内使用的值以及方法都是在组件内定义的,模板值在props值中,使用的方法在methods中定义,props只是定义了可以使用的变量,对应的值在使用组件的使用通过数据绑定v-bind进行绑定,在组件中定义的方法是根实例进行监听的,组件自己的监听方法需要放在template中。

若要在组件中使用data,请使用以下的方式

1
2
3
4
5
6
7
Vue.component('magic-eight-ball', {
data: function () { // 一定要通过函数返回值的形式
return {
possibleAdvice: ['Yes', 'No', 'Maybe']
}
}
}

自定义事件、监听

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
<body>
<div id="app">
<div>
<input v-model="inputValue"/>
<button @click="handleSubmit">提交</button>
</div>
<ul>
<todo-list
v-for="(item, index) of list"
:key="index"
:content="item"
:index="index"
@delete_list="handleDelete" <!--自定义事件,并绑定处理-->
></todo-list>
</ul>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript">
// 使用Vue.component()定义全局组件,可以在挂载的dom内的任何位置通过组件名进行使用
Vue.component('todo-list',{
props: ['content', 'index'], // 定义从外部接受的属性
template: '<li @click="handleClick">{{content}}</li>',
methods:{
handleClick: function (){
this.$emit('delete_list', this.index) // 触发自定义事件,提供回调函数的参数
}
}
})

vm = new Vue({
el: '#app',
data:{
inputValue: '',
list: [ ],
},
methods:{
handleSubmit: function(){
if (this.inputValue !=''){
this.list.push(this.inputValue)
this.inputValue = '' // 做了双向绑定
}
},
handleDelete:function (index) {
this.list.splice(index,1)
},
}
})
</script>

组件用到的属性以及方法都在组件内定义,在template中使用,组件的dom一定要定义在template属性中。组件若想用到根组件的内容的时候在调用组件中使用,通过数据绑定获取根vue的data值,通过事件监听,调用根vue的方法。

注意: HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。Prop 的大小写 (camelCase vs kebab-case)

组件与实例的关系

每个组件都是一个vue实例,都有vue实例的各种方法。

每个项目包含多个vue实例,但是只有一个根实例,根实例可以没有template属性,没有template属性的时候,会自动找挂载点dom,将挂载点下的dom作为template的内容。若使用了template属性,挂载元素的内容都将被忽略,除非模板的内容有分发插槽