响应式数据,组件通讯-父传子,子传父

响应式数据的说明

响应式数据: 把data中的数据挂到vm身上,vm身上的这个数据其实就是响应式的

一旦数据发生了改变,页面中的内容也会跟着改变

$set的使用

  • data中的数据一定要先声明,再使用,动态给对象添加的属性不是响应式的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<p>{{person.name}}---{{person.age}}---{{person.gender}}</p>
</div>

<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
person: {
name: 'zs',
age: 18
}
}
})
</script>

// 动态给data中添加的数据是无效的
// 在vue实例创建的时候,会把data中的数据绑定到vm上,所以data中的数据是响应的
// 但是动态绑定的数据不是响应是的。
vm.person.gender = '男'
  • 如果想要动态绑定数据,并且是响应式的,需要使用vm.$set方法
1
this.$set(this.person, 'gender', '男')

结论:

  • 如果是对象,动态给对象添加或者删除一个属性,vue是检测不到的,所以不是响应的,如果想用动态添加的数据是响应式,需要使用Vue.set(obj, key, value) vm.$set(obj, key ,value)
  • 如果是数组,通过数组的下标或者是数组的长度,vue也是检测不到,所以操作也不是响应式的
    • 使用Vue.set方法
    • 数组的变异的方法,这个方法会改变原数组,能够触发vue的更新。

异步DOM更新以及$nextTick的说明

在vue中数据发生了改变,DOM中的数据也会跟着发生改变,但是这个过程是异步的

vue的数据发生改变之后,DOM不会立即更新,会等到下一次渲染工作执行的时候才会更新DOM

目的:为了提高渲染的性能

1
2
3
4
5
6
7
8
9
10
11
12
clickFn () {
// 数据变化了, view中的内容也要跟着变
this.msg = '你好啊,vue1'
this.msg = '你好啊,vue2'
this.msg = '你好啊,vue3'
this.msg = '你好啊,vue4'
this.msg = '你好啊,vue5'

// 为什么:DOM操作是非常消耗性能的,如果每次操作数据,都立即更新DOM,无疑性能会非常的低,所以vue中会等待数据都修改完成
let result = document.querySelector('p').innerHTML
console.log(result)
}
  • $nextTick方法会在DOM更新之后执行
1
2
3
4
5
6
7
// 在实际开发中,有可能需要在数据改变之后,获取到更新之后的DOM数据
// 这个时候可以使用 $nextTick函数
// 当vue更新完DOM后,会自动调用$nextTick函数,确保在这个函数中可以获取到DOM结构是最新的
this.$nextTick(function() {
let result = document.querySelector('p').innerHTML
console.log(result)
})

组件化开发

组件的概念

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。

在vue中都是组件化开发的,组件化开发就是把一个完整的页面分割成一个一个的小组件。

组件的优点:

  • 容易维护
  • 复用
1
2
3
vue组件分为全局组件和局部组件
全局组件:在所有的vue实例中都能使用
局部组件:只有在当前vue实例中能够使用

全局组件

  • 定义
1
2
3
4
5
6
// 要注册一个全局组件,可以使用 Vue.component(tagName, options)。
// 注册一个全局的组件
// Vue.component(tagName, options)
Vue.component("hello", {
template: '<h3>我是全局组件!</h3>'
});
  • 使用
1
2
3
4
全局组件可以在所有的实例中使用
<div id="app">
<hello></hello>
</div>
  • 注意点:组件的模板有且仅有一个根元素
1
2
template: '<h3>我是全局组件!</h3><p>有两个根元素</p>';  // 错误的用法
template: '<div><h3>我是全局组件!</h3><p>有两个根元素</p></div>';
  • 如果有很多的内容,template可以使用字符串模版
1
2
3
4
5
6
7
8
Vue.component("my-button", {
template: `
<div>
<h1>我是一个标题</h1>
<p>我是一个段落</p>
</div>
`
});

局部组件

1
2
3
4
5
6
7
8
9
10
11
// 在vue实例的内部,通过components属性来定义局部组件
components: {
"my-button": {
template: `
<div>
<h1>我是一个标题</h1>
<p>我是一个段落</p>
</div>
`
}
}

组件是特殊的vue实例

可以将组件看成是一个vue的实例,因此,在vue实例中能配置的属性,在组件中依旧能够配置。

比如:data,method,watch,computed,钩子函数等

注意:组件中data属性必须是一个函数,返回值才是data的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 可以把组件看成一个vue实例
Vue.component("my-button", {
template: `
<div>
<h1 @click="add">我是一个标题</h1>
<p>{{msg}}</p>
</div>
`,
// 组件可以通过data属性提供组件自己的数据,注意,组件的data参数必须是一个函数,不能是用一个对象。
data() {
return {
msg: 'hello vue'
};
},
methods: {
add() {
console.log("哈哈");
}
}

});
  • 组件是一个独立封闭的个体,组件之间的数据是无法相互使用的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var vm = new Vue({
el: '#app',
data: {
outer: '我是实例的数据'
},
});

//可以把组件看成一个vue实例
Vue.component("my-button", {
template: `
<div>
<p>{{inner}}</p> // 正确,组件可以使用自己的数据
<p>{{outer}}</p> // 报错,组件无法使用其他组件的数据
</div>
`,
data() {
return {
inner: '我是组件的数据'
};
}
});

组件通讯

因为组件是一个独立的个体,组件无法使用到外部的数据

但是在真实开发中,多个组件之间是需要相互使用彼此的数据的,因此需要使用组件通讯的技术,让组件之间能够相互传值。

组件通讯分为三类

  • 父组件传递值给子组件
  • 子组件传递值给父组件
  • 非父子组件之间的传值

组件通讯-父传子

  • 定义两个组件
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
Vue.component("parent", {
template: `
<div class="parent">
<p>这是父组件</p>
<son></son>
</div>
`,
data () {
return {
car: '玛莎拉蒂',
month: 1000000
}
}
});

Vue.component("son", {
template: `
<div class="son">
<p>这是子组件</p>
</div>
`
});

<div id="app">
<parent></parent>
</div>
  • 组件的通讯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 在父组件的模版中,给子组件增加一个自定义的属性。
<son :car="car"></son>

2. 子组件通过props属性进行接收
// 接收父组件传递过来的值
props: ['car']

3. 子组件使用父组件传递过来的值
template: `
<div class="son">
<p>这是子组件</p>
<p>这是父组件传递过来的值----{{car}}</p>
</div>
`,

注意:props负责获取父组件的传递过来的,props中的值是只读的,不允许修改

组件通讯-子到父

参考链接:https://blog.csdn.net/jsxiaoshu/article/details/79058940

整体思路

1
2
1. 父组件给子组件注册一个自定义事件
2. 子组件触发这个自定义事件,触发事件时把数据传递给父组件
  • 父组件给子组件注册事件
1
2
3
4
5
6
7
<son @fn='getData'></son>
methods: {
// 父组件中定义了一个方法,用于获取数据
getData () {
console.log("父组件中提供的方法");
}
}
  • 子组件触发自定义事件,并且把要传递的数据作为参数进行传递
1
2
// $emit可以出发当前实例的事件
this.$emit('getData', this.car);
  • 父组件获取值
1
2
3
4
5
6
methods: {
getData (skill) {
console.log("父组件中提供的方法", skill);
this.skill = skill;
}
}