标签:func bind 过程 绑定 update sync value dom 传递参数
本章我们来学习Vue组件通信中的可以算是所有内容,在此之前,您最好掌握Vue的基础语法、指令等内容,同时也建议您查看我其他的文章进行补充。

通过上图顺带给大家说明了父子组件的实现原理,以及组件间传值传DOM的实现思路,那么我们看看Vue的代码来感受一下
模板部分(此处传值也能使用组件内的变量)
<div id="app">
        <!-- 传递一个字符串常量haha -->
         <son v-bind:text="'haha'"/>
</div>js部分
        // 子组件
        var Son = {
            // 要接收的字段名称
            props:['text'], 
            template:`
                <div>
                    {{ text }}
                </div>`
        };
        Vue.component('son',Son);
        // 父组件
        new Vue({
            el:'#app'
        });显示结果很显然是子组件的haha
试想一种情况,由父组件控制子组件的显示,而从子组件中点击X来实现子组件的隐藏,那么实际的控制权确实在父组件

要处理这个问题,大家第一反应应该就是相当通过子组件的点击事件,拿到父组件内控制显示与隐藏的变量并更改就可以了
代码如下
// 隐藏按钮点击函数
methods:{
    clickChild(){
        this.$parent.isShow = false;
    }
}实现是对的,不过
在框架中,我们最好抛开以前的DOM思想,否则我们会无法体会到框架带给我们的思想,而永远沉寂在面向过程中。。。
在Vue中我们用@xxx来给原生DOM元素绑定事件,比如:click、input等。。
那么同时,我们也可以给子组件绑定自定义事件,不论他叫什么名字。举例:
<!-- 父组件 -->
<son v-show="isShow" @callme="callmeFn"/>// 父组件js
methods:{
    callmeFn(params){
        this.isShow = false;
    }
}接下来子组件只用触发这个事件就好了,从低耦合的角度来说,是不是父子各玩各的呢?
// 子组件点击函数中,触发父组件为其绑定的事件
this.$emit('callme','还可以传递参数')对于刚才的例子,我们实际上无需父组件和子组件函数的执行,只需要在子组件点击时同步父组件的isShow的值即可,那么可以这样写
<!-- 父组件内 -->
<son v-show="isShow" :isShow.sync="isShow"/>从子组件中的代码你可以看出原理还是基于事件
// 子组件内
this.$emit('update:isShow','value')要做的只有类似这样3步
let connector = new Vue();connector.$on('事件名',function(params){ });connector.$emit('事件名','value');大家对于on,emit可能已经看得比较痛苦了,有懵逼的吧?那话不多说,直接上源码实现,相信会让你感觉好一点
    var store = {
            once:{},
            fns:{},
            on(key,fn,isOnce){
                this.fns[key]?this.fns[key].push(fn):this.fns[key] = [fn];
            },
            emit(key,value){
                let t = this.fns[key];
                let o = this.once[key];
                if (!t)return;
                t.forEach(fn=>{
                    fn(value);
                });
                if (o)  this.off(key);
            },
            off(key) {
                    delete this.fns[key];
            },
            once(key,fn){
                this.once[key] = true;
                this.on(key,fn);
            }
        }原理其实就是一个对象用key存储着事件名,用value存储着函数!
看下面的功能,9宫格的6个,看看这些组件样子一样却又各不相同,因此,我们可以尝试由父组件给他们不同的DOM来体现他们的不同,子组件只需要做一些对他们公共特点的编写即可

如果子元素的大部分所有内容由父元素来定制,子组件内尽量单一、简单,该组件就算是低耦合、高内聚了。
那么子组件中给父组件留下的内容区域如何来实现呢? 答案是:slot(插槽)
<!-- 子组件 -->
<div>
    <!--一个默认的坑-->
    <slot></slot>
</div><!-- 父组件 -->
<!-- 使用子组件 -->
<son>
    <!--传递的DOM-->
    <template v-slot:default>
        <button>给子的按钮</button>
    </template>
</son><!-- 子组件 -->
<div>
    <!-- 定制上半部分 -->
    <slot name="head"></slot>
    <!-- 定制下半部分 -->
    <slot name="foot"></slot>
</div><!-- 父组件 -->
<!-- 使用子组件 -->
<son>
    <!--传递的DOM-->
    <template v-slot:head>
        <button>给头的按钮</button>
    </template>
     <template v-slot:foot>
        <button>给底部的按钮</button>
    </template>
</son>
思路整理: 这一组ul+li我们把他想象成一个组件,他接收一个数组,通过v-for帮我们渲染,数据如下
// 父组件数据
todos: [
        {
            id: 0,
            text: 'ziwei0',
            isComplete: true
        },
        {
            text: 'ziwei1',
            id: 1,
            isComplete: true
        },
        {
            text: 'ziwei2',
            id: 2,
            isComplete: false
        },
        {
            text: 'ziwei3',
            id: 3,
            isComplete: false
        }
];父组件把该对象传递给子组件
<son :todos="todos"></son>剩下的就交给子组件,让它来处理具体的业务吧! 对吗?

不是说好了,让子组件功能尽量单一,高内聚、低耦合的么,它都处理业务了,还谈啥公共组件呢,复用性不高,pass!
因此我们将业务判断功能留给父组,子组件这么写
 <!--子组件-->
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <slot>
      </slot>
    </li>
  </ul>那么问题来了,父组件是不是要传递DOM作为slot的值呢?
    <!--父组件-->
    <son :todos="todos">
        <template v-slot:default>
            <span>?</span>
            <span>内容</span>
        </template>
    </son>糟糕,父组件把todos都传递进去了,可现在要通过每一个todo来做业务处理啊,看张图

因此,我们使用2.6的新功能slotProps,看slot 传值
 <!--子组件-->
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <slot :todo="todo">
      </slot>
    </li>
  </ul>看父组件如何接收,看template那里(固定写法) slotProps相当于内置变量
<!--父组件-->
    <son :todos="todos">
                <template v-slot:default="slotProps">
                    <span v-if="slotProps.todo.isComplete">?</span>
                    <span>{{slotProps.todo.text}}</span>
                </template>
            </son>搞定!如果你喜欢我的文章,可以关注我,如果忍不住想天天看到我,可以联系我加入我们的前端讨论群
标签:func bind 过程 绑定 update sync value dom 传递参数
原文地址:https://www.cnblogs.com/qidaoxueyuan/p/12378631.html