## 组件通信
* 父子组件通信
* 兄弟组件通信
* 跨多层组件通信
* 任意组件
### 父子通信
1. **父组件通过props传递数据给子组件,子组件通过emit发送数据给父组件**。
典型的单向数据流,父组件通过props传递数据,**子组件不能直接修改props**,而是必须通过**发送事件**的方式告知父组件修改数据。
2. 这两种方式**还可以用语法糖v-model来直接实现**。
v-model默认会解析成**名为value的prop和名为Input的事件**。这种语法糖的方式是典型的双向绑定,常用于UI控件上,但是根本还是通过事件的方法让父组件修改数据。
3. 我们还可以通过访问$parent或者$children对象来访问组件实例中的方法和数据。
4. $listeners和.sync这两个属性
$listenters属性会将父组件的(不含.native修饰器的)v-on事件监听器传递给子组件,子组件可以通过访问$listeners来自定义监听器。
`.sync`属性是个语法糖,可以很简单的实现子组件与父组件通信
~~~
<!--父组件中-->
<input :value.sync="value" />
<!--以上写法等同于-->
<input :value="value" @update:value="v => value = v"></comp>
<!--子组件中-->
<script>
this.$emit('update:value', 1)
</script>
~~~
### 兄弟组件通信
可以通过查找父组件中的子组件实现,也就是**this.$parent.$children**,在$children中可以通过组件的**name**查询需要的组件实例,然后进行通信。
或者**this.$parent.$refs['name']**
### 跨多层次组件通信
可以使用Vue2.2新增的API provide/inject,虽然文档中不推荐直接使用在业务中,但是如果用的好的话,还是有用的。
假设有父组件 A,然后有一个跨多层级的子组件 B
~~~
// 父组件 A
export default {
provide: {
data: 1
}
}
// 子组件 B
export default {
inject: ['data'],
mounted() {
// 无论跨几层都能获得父组件的 data 属性
console.log(this.data) // => 1
}
}
~~~
### 任意组件
这种方式可以通过Vuex或者Event Bus解决,如果不怕麻烦,可以使用这种方式解决上述所有的通信情况
~~~
import Vue from 'vue';
var bus=new Vue();
export default bus;
~~~
~~~
import Bus from '../common/bus.js';
gotoDetail(status,questionId){
let obj={
status,
questionId,
}
Bus.$emit('gotoDetail',obj);
},
~~~
~~~
created(){
Bus.$on('gotoDetail',(obj)=>{
console.log(obj);
this.currentQuestion=obj;
this.flag++;
})
},
~~~
## extend能做什么
很少用到,作用是**扩展组件生成一个构造器**,通常会与$mount一起使用。
~~~
//创建组件构造器
let Component = Vue.extend({
template:'<div>test</div>'
});
//挂载到#app上
new Component().$mount('#app')
//除了上面的方法,还可以用来扩展已有的组件
let SuperComponent = Vue.extend(Component);
new SuperComponent({
created(){
console.log(1)
}
})
new SuperComponent().$mount('#app')
~~~
### mixin和mixins区别
mixin用于**全局混入,会影响到每个组件实例,通常插件都是这样做初始化的**。
~~~
Vue.mixin({
beforeCreate(){
//逻辑
//这种方式会影响到每个组件的beforeCreate钩子函数
}
})
~~~
虽然文档不建议我们在应用中直接使用mixin,但是如果不滥用的话也是有帮助的,比如可以全局混入封装好的ajax或者一二线工具函数。
mixins应该是我们最常使用的**扩展组件的方式**了。如果**多个组件有相同的业务逻辑**,就可以将**这些逻辑剥离出来**,通过mixins混入代码,比如**上拉下拉加载数据**等。
另外,mixins混入的钩子函数会先于组件内的钩子函数执行,并且遇到同名选项的时候会选择性的进行合并。
### computed和watch区别
computed是计算属性,**依赖其他属性计算值**,并且c**omputed的值有缓存**,**只有当计算值变化才会返回内容**。
watch监听到值的变化就会执行回调函数,在回调中进行一些逻辑操作
* 一般需要依赖别的属性来动态获取值的可以用computed
* 对应监听到值变化需要做一些赋值业务逻辑的情况使用watch
* computed和watch还支持对象的写法
~~~
vm.$watch('obj',{
//深度遍历
deep: true,
//立即触发
immediate: true,
//执行的函数
handler:function(val, oldVal){}
})
var vm = new Vue({
data:{a:1},
computed:{
aPlus:{
//this.aPlus触发
get:function(){
return this.a +1;
},
//this.aplus=1是触发
set:funcion(v){
this.a = v-1;
}
}
}
})
~~~
### keep-alive组件有什么作用
如果你需要组件切换时,**保存一些组件的状态防止多次渲染**,就可以使用keep-alive组件包裹需要保存的组件。
对应keep-alive组件,有两个独有的声明周期钩子函数,分别为`activated`和`deactivated`。用`keep-alive`包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行`deactivated`钩子函数,命中缓存渲染后会执行`actived`钩子函数。
### v-show和v-if区别
`v-show`只是在`display: none`和`display: block`之间切换。无论初始条件是什么都会被渲染出来,**后面只需要切换css**,dom还是一直保留着的。
v-show:**在初始渲染是有更高的开销,但切换开销很小,适合于频繁切换的场景**。
`v-if`false时组件就不会被渲染,知道条件为true,并且**切换条件时会触发销毁/挂载组件**,
v-if:切换时开销更高,适合不经常切换的场景。
v-if的这种**惰性渲染机制**,可以在必要的时候采取渲染,**减少整个页面的初始渲染开销**。
### 组件中data什么时候可以使用对象
组件复用时,**所有组件实例都会共享data,如果data是对象的话,就会造成一个组件修改data以后会影响到其他所有组件,所以需要将data写出函数,每次用到就调用一次函数获取新的数据。**
当我们使用**new Vue()的方式的时候**,无论我们将data设置为对象还是函数都是可以的,**因为new Vue()的方式生成一个根组件**,改组件不会复用,也就不存在共享data的情况了。
- 空白目录
- 双樾
- JS基础知识
- JS-WEB-API
- 开发环境
- 运行环境
- ES6
- 原型
- 异步
- 虚拟dom
- mvvm
- 组件化和React
- hybrid
- 其他
- 补充
- 技巧
- 快乐动起来呀
- css
- 掘金小册子
- js基础知识
- ES6知识点
- JS异步
- JS进阶知识
- 思考题
- DevTools Tips
- 浏览器基础知识
- 浏览器缓存机制0
- 浏览器渲染原理
- 安全防范知识点0
- 从V8中看JS性能优化0
- 性能优化琐碎事
- Webpack性能优化0
- 实现小型打包工具0
- React和Vue
- Vue生命周期
- vue基础知识点
- Vue响应式
- vue高级
- React基础
- Vue.js技术解密
- 准备工作
- 数据驱动
- new Vue()
- vue实例挂载
- 组件化
- 深入响应式原理
- 编译
- 扩展
- Vue Router
- Vuex