vue.js学习笔记七

Posted -恰饭第一名-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue.js学习笔记七相关的知识,希望对你有一定的参考价值。

一、父子组件的访问方式:$children

  • 有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件
  • 父组件访问子组件:使用$chilren$refs reference(引用)
  • 子组件访问父组件:使用$parent

  • 我们先来看下$children的访问
  • this.$children是一个数组类型,它包含所有子组件对象
  • 我们这里通过一个遍历,取出所有子组件的message状态
<body>
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <!-- <my-cpn></my-cpn>
        <y-cpn></y-cpn> -->

        <cpn ref="aaa"></cpn>
        <button @click="btnClick">按钮</button>
    </div>

    <template id="cpn">
      <div>我是子组件</div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue(
            el: "#app",
            data: 
                message: "你好啊"
            ,
            methods: 
                btnClick() 
                    // 1.$children
                    // console.log(this.$children);
                    // for (let c of this.$children) 
                    //     console.log(c.name);
                    //     c.showMessage();
                    // 
                    // console.log(this.$children[2].name);

                    // 2. $refs => 对象类型, 默认是一个空的对象 ref = "bbb"
                    console.log(this.$refs.aaa.name);
                
            ,
            components: 
                cpn: 
                    template: "#cpn",
                    data() 
                        return 
                            name: "我是子组件的name"
                        
                    ,
                    methods: 
                        showMessage() 
                            console.log("showMessage");
                        
                    
                ,
            
        )
    </script>



二、父子组件的访问方式:$refs

  • $children的缺陷
  • 通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值
  • 但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化
  • 有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs
  • $refs的使用
  • $refs和ref指令通常是一起使用的
  • 首先,我们通过ref给某一个子组件绑定一个特定的ID
  • 其次,通过this.$refs.ID就可以访问到该组件了
<child-cpn1 ref="child1"></child-cpn1>
    <child-cpn2 ref="child2"></child-cpn2>
    <button @click="showRefsCpn">通过refs访问子组件</button>
    <script>
      showRefsCpn()
        console.log(this.$refs.child1.message);
        console.log(this.$refs.child2.message);
      
      
    </script>



三、父子组件的访问方式:$parent

  • 如果我们想在子组件中直接访问父组件,可以通过$parent
  • 注意事项:
  • 尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做
  • 子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了
  • 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题
  • 另外,更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于调式和维护
    <div id="app">
        <parent-cpn></parent-cpn>
    </div>

    <template id="parentCpn">
      <child-cpn></child-cpn>
    </template>

    <template id="childCpn">
      <button @click="showParent">显示父组件信息</button>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component("parent-cpn", 
            template: "#parentCpn",
            data() 
                return 
                    message: "我是父组件,嘿嘿"
                
            ,
            components: 
                "child-cpn": 
                    template: "#childCpn",
                    methods: 
                        showParent() 
                            console.log(this.$parent.message);
                        
                    
                
            
        )

        const app = new Vue(
            el: '#app',
            data: 
                message: '你好啊'
            
        )
    </script>



四、非父子组件通信

  • 非父子组件关系包括多个层级的组件,也包括兄弟组件的关系
  • 在Vue1.x的时候,可以通过$dispatch$broadcast完成
  • $dispatch用于向上级派发事件
  • $broadcast用于向下级广播事件
  • 但是在Vue2.x都被取消了
  • 在Vue2.x中,有一种方案是通过中央事件总线,也就是一个中介来完成
  • 但是这种方案和直接使用Vuex的状态管理方案还是逊色很多



五、为什么使用slot

  • slot翻译为插槽
  • 在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽
  • 插槽的目的是让我们原来的设备具备更多的扩展性
  • 比如电脑的USB我们可以插入U盘,硬盘,手机,音响,键盘,鼠标等等
  • 组件的插槽:
  • 组件的插槽也是为了让我们封装的组件更加具有扩展性
  • 让使用者可以决定组件内部的一些内容到底展示什么
  • 例子:移动网站中的导航栏。
  • 导航栏我们必然会封装成一个插件,比如nav-bar组件。
  • 一旦有了这个组件,我们就可以在多个页面中复用了
  • 但是,每个页面的导航是一样的吗?

六、如何封装这类组件呢?

  • 抽取共性,保留不同
  • 最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽
  • 一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容
  • 是搜索框,还是文字,还是菜单。由调用者自己来决定

七、slot基本使用

  • 如何使用slot?
  • 在子组件中,使用特殊的元素<slot>就可以为子组件开启一个插槽
  • 该插槽插入什么内容取决父组件如何使用
  • 我们通过一个简单的例子,来给子组件定义一个插槽:
  • <slot>中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容
  • 有了这个插槽后,父组件如何使用呢?
<body>
    <div id="app">
        <my-cpn></my-cpn>
        <my-cpn>
            <h2>我是替换插槽的内容</h2>
            <p>我也是替换插槽的内容</p>
        </my-cpn>
    </div>
    <template id="myCpn">
      <div>
        <slot>我是一个插槽中的默认内容</slot>
      </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component("my-cpn", 
            template: "#myCpn"
        )
        let app = new Vue(
            el: "#app"
        )
    </script>
</body>

八、具名插槽slot

  • 当子组件的功能复杂时,子组件的插槽可能并非是一个
  • 比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边
  • 那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?
  • 这个时候,我们就需要给插槽起一个名字了
  • 如何使用具名插槽呢?
  • 只要给slot元素一个name属性即可
  • <slot name="myslot"></slot>
  • 下面这个例子,我们先不对导航组件做非常复杂的封装,先了解具名插槽的用法
<body>
    <div id="app">
        <!-- 没有传入任何内容 -->
        <my-cpn></my-cpn>
        <!-- 传入某一个内容 -->
        <my-cpn>
            <span slot="left">我是返回</span>
        </my-cpn>
        <!-- 传入所有的内容 -->
        <my-cpn>
            <span slot="left">我是返回</span>
            <span slot="center">我是标题</span>
            <span slot="right">我是菜单</span>
        </my-cpn>
    </div>
    <template id="myCpn">
      <div>
        <slot name="left">我是左侧</slot>
        <slot name="center">我是中间</slot>
        <slot name="right">我是右侧</slot>
      </div>
      </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component("my-cpn", 
            template: "#myCpn"
        )
        let app = new Vue(
            el: "#app"
        )
    </script>
</body>

九、编译作用域

<div id="app">
        <my-cpn v-show="isShow"></my-cpn>
    </div>
    <template id="myCpn">
      <h2>我能不能显示出来呢</h2>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        Vue.component("my-cpn", 
            template: "#myCpn",
            data() 
                return 
                    isShow: false
                
            
        )
        let app = new Vue(
            el: "#app",
            data: 
                isShow: true
            
        )
    </script>
  • my-cpn v-show=“isShow”>中,我们使用了isShow属性。
  • isShow属性包含在组件中,也包含在Vue实例中。
  • 答案:最终可以渲染出来,也就是使用的是Vue实例的属性。

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

    <div id="app">
        <cpn v-show="isShow"></cpn>
        <cpn v-for="item in names"></cpn>
    </div>


    <template id="cpn">
    <div>
      <h2>我是子组件</h2>
      <p>我是内容,哈哈哈</p>
      <button v-show="isShow">按钮</button>
    </div>
  </template>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue(
            el: "#app",
            data: 
                message: "你好啊",
                isShow: true
            ,
            components: 
                cpn: 
                    template: "#cpn",
                    data() 
                        return 
                            isShow: false
                        
                    
                
            
        )
    </script>

十、作用域插槽:准备

  • 父组件替换插槽的标签,但是内容由子组件来提供
  • 我们先提一个需求:
  • 子组件中包括一组数据,比如:pLanguages: ['javascript', 'Python', 'Swift', 'Go', 'C++']
  • 需要在多个界面进行展示
  • 某些界面是以水平方向一一展示的,
  • 某些界面是以列表形式展示的,
  • 某些界面直接展示一个数组
  • 内容在子组件,希望父组件告诉我们如何展示,怎么办呢?
  • 利用slot作用域插槽就可以了

十一、作用域插槽:使用

  • 在父组件使用我们的子组件时,从子组件中拿到数据:
  • 我们通过获取到slotProps属性
  • 在通过slotProps.data就可以获取到刚才我们传入的data了
  <div id="app">
        <cpn></cpn>
        <cpn>
            <!-- 目的是获取子组件中的pLanguages -->
            <template slot-score="slot">
              <!-- <span v-for="item in slot.data">item</span> -->
              <span>slot.data.join("-")</span>
          </template>
        </cpn>
        <cpn>
            <template slot-score="slot">
               <!--<span v-for="item in slot.data">item * </span>-->
            <span>slot.data.join("-")</span>
          </template>
        </cpn>
    </div>

    <template id="cpn">
      <div>
          <slot :data="pLanguages">
            <ul>
              <li v-for="item in pLanguages">item</li>
            </ul>
          </slot>
      </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue(
            el: "#app",
            data: 
                message: "你好啊"
            ,
            components: 
                cpn: 
                    template: "#cpn",
                    data() 
                        return 
                            pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift']
                        
                    
                
            
        )
    </script>

以上是关于vue.js学习笔记七的主要内容,如果未能解决你的问题,请参考以下文章

vue.js学习笔记七

Vue学习笔记目录

北风网-Vue.js 学习笔记

Vue.js学习笔记 - 起步

vue.js学习笔记一

vue.js学习笔记一