💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 组件通信 * 父子组件通信 * 兄弟组件通信 * 跨多层组件通信 * 任意组件 ### 父子通信 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的情况了。