vue.js学习笔记七

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

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

  • 我们先来看下$children的访问
  • this.$children是一个数组类型,它包含所有子组件对象
  • 我们这里通过一个遍历,取出所有子组件的message状态
<body>
    <div id="app">
        <cpn>cpn>
        <cpn>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组件。
  • 一旦有了这个组件,我们就可以在多个页面中复用了
  • 但是,每个页面的导航是一样的吗?
    vue.js学习笔记七_第1张图片

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

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

七、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>

vue.js学习笔记七_第2张图片

八、具名插槽slot

  • 当子组件的功能复杂时,子组件的插槽可能并非是一个
  • 比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边
  • 那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?
  • 这个时候,我们就需要给插槽起一个名字了
  • 如何使用具名插槽呢?
  • 只要给slot元素一个name属性即可
  • 下面这个例子,我们先不对导航组件做非常复杂的封装,先了解具名插槽的用法
<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实例的属性。

  • 父组件模板的所有东西都会在父级作用域内编译:子组件模板的所有东西都会在子级作用域内编译
  • 而我们在使用的时候,整个组件的使用过程是相当宇在父组件中出现的
  • 那么他的作用域就是父组件,使用的属性也是属于父组件的属性
  • 因此,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>
            
            <template slot-score="slot">
              
              <span>{{slot.data.join("-")}}span>
          template>
        cpn>
        <cpn>
            <template slot-score="slot">
               
            <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>

你可能感兴趣的:(JavaScript,vue,学习笔记)