• 14 小程序-组件通信修饰符、插槽、前端模块化开发


    1.父子通信扩展

    1.1.-父访问子组件的访问方式 $children  $refs(实例中加标签)

            某些时候,父子组件进行调用某些方法,实现功能,这里就要用的父子组件的访问方式的修饰符,有时候我们需要父组件直接通过对象来访问子组件,子组件直接访问父组件,或者是子组件访问跟组件。

    • 父组件访问子组件:使用$children或$refs(reference 引用意思)

             其中¥children也是数组,子组件对象类型是数组类型是vuecomponent

    • 子组件访问父组件:使用$parent

    image

    image

         一般来说,我们也不会用¥children拿子组件东西(下标拿毕竟不安全,万一加其他组件,容易出错,而且除非是拿全部组件,才会用$children),我们用$refs,如果组件不加内容则为空.

          $refs=》对象类型,默认是空对象,加ref=‘bbb’

    image

          必须在子组件使用时候,在父实例中加上ref=‘XXX’,
    然后父组件监听事件中给予使用this.$refs
    <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>
    <cpn ref="aaa"></cpn>
    <button @click="btnclick">按钮</button>
    </div>

    <template id="cpn">
    <h2>我是子组件</h2>
    </template>
    <script>
    const app=new Vue({
    el:'#app',
    data:{

    },
    methods:{
    btnclick(){
    console.log(this.$children);
    console.log('---------')
    console.log(this.$refs.aaa.name);

    }
    },
    components:{
    cpn:{
    template:'#cpn',
    methods:{
    showMessage222(){
    console.log('showMessage222')
    }
    },
    data(){
    return{
    name:'我是子组件的name'
    }
    }
    }
    }
    })
    </script>

    1.2.-子访问父组件的访问方式 parent  root

          当然一般很少这么使用,因为子组件还是建议相对独立,否则耦合性太高

    <div id="app">
        <cpn></cpn>
    
    </div>
    <template id="cpn">
        <div>
            <h2>我是cpn组件</h2>
            <ccpn></ccpn>
        </div>
    </template>
    <template id="ccpn">
        <div>
            <div>我是子组件</div>
            <button @click="btnclick()">按钮</button>
        </div>
    </template>
    <script>
        const app=new Vue({
            el:'#app',
            data:{
                message:'你好啊'
            },
            components:{
                cpn:{
                    template:'#cpn',
                    data(){
                        return {
                            name:'我是cpn组件的name'
    
                        }
                    },
                    components: {
                        ccpn:{
                            template:'#ccpn',
                            methods:{
                                btnclick(){
                                    //    访问父组件
                                    console.log(this.$parent);
                                    console.log(this.$parent.name);
                                }
                            }
                        }
                    }
    
                },
    
            }
    
        })
    
    
    </script>

         可以使用this.$root,直接访问vue实例,因为$parent访问的是父组件

    image

        this.¥root.message也就可以访问到“你好啊”

    2. 插槽slot 使用

    2.1 插槽slot基本使用

    slot翻译为插槽:

    • 在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽。
    • 插槽的目的是让我们原来的设备具备更多的扩展性。
    • 比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。

    组件的插槽:

    • 组件的插槽也是为了让我们封装的组件更加具有扩展性。
    • 让使用者可以决定组件内部的一些内容到底展示什么。

    栗子:移动网站中的导航栏。

    • 移动开发中,几乎每个页面都有导航栏。
    • 导航栏我们必然会封装成一个插件,比如nav-bar组件。
    • 一旦有了这个组件,我们就可以在多个页面中复用了。

    但是,每个页面的导航是一样的吗?No,我以京东M站为例

    <template id="cpn">
        <div>
            <h2>我是组件</h2>
            <p>我是组件,哈哈哈</p>
            <slot></slot>
        </div>
    </template>

          如何使用呢?

    最基本的使用如下:引用的组件内部进行标签替换。

    <div id="app">
        <cpn><button>按钮</button></cpn>
        <cpn><span>哈哈</span></cpn>
        <cpn><i>合伙</i></cpn>
        <cpn><button>按钮</button></cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>我是组件</h2>
            <p>我是组件,哈哈哈</p>
            <slot></slot>
        </div>
    </template>

           当然如果说某个插槽非常常用,比方说按钮,那么我们给予模板template添加默认插槽:则效果与上面一样

    <div id="app">
        <cpn></cpn>
        <cpn><span>哈哈</span></cpn>
        <cpn><i>合伙</i></cpn>
        <cpn></cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>我是组件</h2>
            <p>我是组件,哈哈哈</p>
            <slot><button>按钮</button></slot>
        </div>
    </template>

    2.2 插槽slot-具名插槽

       具名插槽,意思是给每个slot添加个名字,那么使用它时,如果没有名字,进行修改插槽,那么则默认给没有名字的插槽进行变化

    </head>
    <body>
    <div id="app">
        <cpn><button>按钮</button></cpn>
    </div>
    <template id="cpn">
        <div>
            <slot name="left"><span>左边</span></slot>
            <slot name="center"><span>中间</span></slot>
            <slot name="right"><span>右边</span></slot>
            <slot>哈哈哈</slot>
        </div>
    </template>

         那么给予名字时候,不能用name,而是用slot=‘left’名字即可

    <div id="app">
        <cpn><button slot="left">按钮</button></cpn>
    </div>
    <template id="cpn">
        <div>
            <slot name="left"><span>左边</span></slot>
            <slot name="center"><span>中间</span></slot>
            <slot name="right"><span>右边</span></slot>
            <slot>哈哈哈</slot>
        </div>
    </template>

    2.3 编译作用域与插槽作用域

    在真正学习插槽之前,我们需要先理解一个概念:编译作用域。官方对于编译的作用域解析比较简单,我们自己来通过一个例子来理解这个概念:

    我们来考虑下面的代码是否最终是可以渲染出来的:

    • <my-cpn v-show="isShow"></my-cpn>中,我们使用了isShow属性。
    • isShow属性包含在组件中,也包含在Vue实例中。

    答案:最终可以渲染出来,也就是使用的是Vue实例的属性。

    为什么呢?

    • 官方给出了一条准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
    • 而我们在使用<my-cpn v-show="isShow"></my-cpn>的时候,整个组件的使用过程是相当于在父组件中出现的。
    • 那么他的作用域就是父组件,使用的属性也是属于父组件的属性。
    • 因此,isShow使用的是Vue实例中的属性,而不是子组件的属性。


    <div id="app">
    <!--    这里v-show使用实例的,当成最简单的变量,去vue实例作用域找-->
        <cpn v-show="isShow"></cpn>
    <!--    这里item也是去vue实例里面找-->
        <cpn v-for="item in names"></cpn>
    </div>
    
    <template id="cpn">
        <div>
            <h2>我是子组件</h2>
            <p>我是子组件,哈哈哈</p>
    <!--        这里用的是子组件的作用域isShow-->
            <button v-show="isShow">按钮</button>
        </div>
    </template>
    <script>
        const app=new Vue({
            el:'#app',
            data:{
                message:'你好啊',
                isShow:true
            },
            components:{
                cpn:{
                    template:'#cpn',
                    data(){
                        return{
                            isShow:false
                        }
                    }
                }
            }
        })
    </script>

    image

            作用域插槽-

    作用域插槽是slot一个比较难理解的点,而且官方文档说的又有点不清晰。这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会:

    父组件替换插槽的标签,但是内容由子组件来提供。

    我们先提一个需求:子组件中包括一组数据,比如:pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++']

    需要在多个界面进行展示:

    • 某些界面是以水平方向一一展示的,
    • 某些界面是以列表形式展示的,
    • 某些界面直接展示一个数组

            内容在子组件,比方说子组件按逗号分隔,希望父组件告诉我们如何展示,怎么办呢?利用slot作用域插槽就可以了,我们来看看子组件的定义:

    image


    <body>
    <div id="app">
        <cpn></cpn>
        <cpn>
    <!--        目的 获取子组件的planguages  vue2.5以前版本-->
            <template slot-scope="slot">
                <span v-for="item in slot.data">{{item}}-</span>
            </template>
        </cpn>
        <cpn>
            <!--        目的 获取子组件的planguages  vue2.5以前版本-->
            <template slot-scope="slot">
    <!--            join的作用是将数组转为字符串,每个数组元素以某种方式拼接-->
                <span >{{slot.data.join('=')}}</span>
            </template>
        </cpn>
    </div>
    
    <template id="cpn">
        <div>
            <slot v-bind:data="planguages">
                <ul>
                    <li v-for="item in planguages"> {{item}}</li>
                </ul>
            </slot>
        </div>
    </template>
    
    <script>
        const app=new Vue({
            el:'#app',
            data:{
                message:'你好啊'
            },
            components:{
                cpn:{
                    template:'#cpn',
                    data(){
                        return{
                            planguages:['JavaScript', 'Python', 'Swift', 'Go', 'C++']
                        }
                    }
                }
            }
        })
    </script>

    在父组件使用我们的子组件时,从子组件中拿到数据:

    • 我们通过<template slot-scope="slotProps">获取到slotProps属性
    • 在通过slotProps.data就可以获取到刚才我们传入的data了

    image

    3.前端模块化开发

          客户端需要完成的事情越来越多,代码量也是与日俱增。为了应对代码量的剧增,我们通常会将代码组织在多个js文件中,进行维护。

    但是这种维护方式,依然不能避免一些灾难性的问题。

           但是当js文件过多,比如有几十个的时候,弄清楚它们的顺序是一件比较同时的事情。而且即使你弄清楚顺序了,也不能避免上面出现的这种尴尬问题的发生。

          闭包解决了变量引用冲突风险,但是造成了变量引用困难的问题。我们可以使用匿名函数来解决方面的重名问题,在aaa.js文件中,我们使用匿名函数

    image

           但是如果我们希望在main.js文件中,用到flag,应该如何处理呢?显然,另外一个文件中不容易使用,因为flag是一个局部变量。我们可以使用将需要暴露到外面的变量,使用一个模块作为出口,什么意思呢?

    来看下对应的代码:我们做了什么事情呢?

    • 非常简单,在匿名函数内部,定义一个对象。
    • 给对象添加各种需要暴露到外面的属性和方法(不需要暴露的直接定义即可)。
    • 最后将这个对象返回,并且在外面使用了一个MoudleA接受。

    image

             接下来,我们在man.js中怎么使用呢?

    • 我们只需要使用属于自己模块的属性和方法即可

    这就是模块最基础的封装,事实上模块的封装还有很多高级的话题:

    • 但是我们这里就是要认识一下为什么需要模块,以及模块的原始雏形。
    • 幸运的是,前端模块化开发已经有了很多既有的规范,以及对应的实现方案。

    常见的模块化规范:

    • CommonJS是规范,具体实现是node.js实现
    • AMD
    • CMD
    • ES6的Modules

        模块化最重要的两点是导入和导出,可以理解为导出一般是return  obj',导入就是用的时候。下面写法是在node中才行,因为需要环境解析

      CommonJS导出  moudle.exports        CommonJS的导入  require('路径')

    imageimage

    3.1. ES6里面的Modules模块化操作

           ES6里面给予模块化开发提供了两个函数 import和export。 

           我们使用export指令导出了模块对外提供的接口,下面我们就可以通过import命令来加载对应的这个模块了

    • export

    导出变量(边导出边定义),      另外一种写法(先定义,后导出):

    imageimage

    也可以输出函数或者输出类

    imageimage

           某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名,这个时候就可以使用export default

    image

          我们来到main.js中,这样使用就可以了,这里的myFunc是我自己命名的,你可以根据需要命名它对应的名字,切记default导入时不需要大括号,但有且仅有一个,否则出错。

    image

        另外,需要注意:export default在同一个模块中,不允许同时存在多个。

    • import命令来加载对应的这个模块了

    1.首先,我们在HTML代码中引入两个js文件,并且类型需要设置为module,表示我们这个js文件使用模块化思想开发,意味着这个js是个模块,单独模块具有单独的作用域,这样即便两个js文件中都有同名变量和函数都不存在命名冲突问题。

    image

    2.import指令用于导入模块中的内容,比如main.js的代码

    image

    如果我们希望某个模块中所有的信息都导入,一个个导入显然有些麻烦:

    • 通过*可以导入模块中所有的export变量
    • 但是通常情况下我们需要给*起一个别名,方便后续的使用

    image

    整体代码效果如下:

    image








  • 相关阅读:
    css3 object-fit详解
    Timing path
    IUS
    FIFO深度
    UVM中的class--2
    UVM中的class
    Binding
    Concurrent Assertion
    Immediate assertion
    sdf
  • 原文地址:https://www.cnblogs.com/rango0550/p/14034209.html
Copyright © 2020-2023  润新知