• Vue组件间传值



    1. 父组件向子组件传值

    1.1 描述

    1. 父组件以属性的形式绑定值到子组件身上。

    2. 子组件通过使用属性 props 接收(props 是单向数据流【只读属性】:当父组件的属性变化时,将传导给子组件,但是反过来不会,即子组件中不可以修改父组件的值,应该通过给子组件传数据的父组件修改)

    1.2 props接收数据:

    语法:

    props: 数组 | 对象

    数组方式接收:

    • 此方式,一般用于你自己定义组件给自己所用,是一种简写方式

    • 数组中的元素就是你自定义的属性名称(注意这里是自定义的属性名称,而不是父组件数据源中的数据名称)

    • 示例:

      子组件(child.vue):

      <template>
      <div>
          <div class="title">childdiv>
          <br />
          <div>{{ title }}div>
          div>
      template>
      
      <script>
          export default {
              // 在vue中接受父组件通过自定义属性传过来的数据,通过配置props来接受
              props: ["title"],
              // 在方法中得到数据
              created() {
                  console.log(this.title);
              },
          };
      script>
      
      <style lang="scss" scoped>
          .title {
              color: red;
          }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24

      父组件(App.vue):

      <template>
      <div>
          <h3 class="title">App组件h3>
          <hr />
          
          
          
          <child :title="title" />
          div>
      template>
      
      <script>
      
          import child from "./components/child.vue";
      
          export default {
              components: {
                  child,
              },
              data() {
                  return {
                      title: "我是一个显示内容",
                  };
              },
          };
      script>
      
      <style lang="scss" scoped>style>
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29

      在这里插入图片描述

    对象方式接收:

    • 一般用于,封装的组件提供给别人使用,它可以限制属性的类型和默认值

    • 示例:

      子组件(child.vue):

      <template>
      <div>
          <div class="title">child组件div>
          <br />
          <div>{{ title }}--{{ age }}div>
          div>
      template>
      
      <script>
          export default {
              props: {
                  // key名称就是你自定义属性名称
                  // 类型首字母大写
                  // attrtitle: String
                  title: {
                      // 接收的数据类型
                      type: String,
                      // 直接给值 [基础类型] | 回调函数 [基础类型和引用类型都可以,引用类型设置默认值必须是此方案]
                      default: "我是一个字符串",
                  },
                  // 自定义方法验证接收的数据
                  age: {
                      type: Number,
                      default: () => 10,
                      // 验证操作
                      validator: (value) => {
                          if (value > 90) {
                              // 返回一个警告
                              return false;
                          }
                          return true;
                      }
                  },
              },
          };
      script>
      
      <style lang="scss" scoped>
          .title {
              color: red;
          }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42

      父组件(App.vue):

      <template>
      <div>
          <h3 class="title">App组件h3>
          <hr />
          <child :title="title" :age="100" />
          <child />
          <child :title="'100'" />
          div>
      template>
      
      <script>
      
          import child from "./components/child.vue";
      
          export default {
              components: {
                  child,
              },
              data() {
                  return {
                      title: "我是一个显示内容",
                  };
              },
          };
      script>
      
      <style lang="scss" scoped>style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27

      在这里插入图片描述

    2. 子组件向父组件传值

    上文提到props 是单向数据流,子组件中不可以修改父组件的值,应该通过给子组件传数据的父组件修改,这样设计是为了防止子和父在修改数据时,造成的数据混乱。

    在 Vue 中,如果子组件修改了父组件传过来的数据,控制台会报一个警告,但在 React 中会直接报错。

    那么子组件要怎么向父组件传值呢?

    有两种方式:

    1. 子组件用$emit()定义自定义事件,$emit()第一个参数为 自定义的事件名称 第二个参数为需要传递的数据;父组件用v-on(@)绑定子组件定义的自定义事件名,监听子组件的事件,实现通信
    2. 父组件直接把修改数据的方法以属性的方式传给子组件(通过形参方式传递)

    方法2实现:

    父组件:

    <template>
    <div>
        <h3 class="title">App组件h3>
        <hr />
        
        <child :title="title" :age="age" :setAge="setAge" />
    div>
    template>
    
    <script>
        import child from "./components/child.vue";
    
        export default {
            components: {
                child,
            },
            data() {
                return {
                    title: "我是一个显示内容",
                    age: 80,
                };
            },
            methods: {
                setAge(n = 1) {
                    this.age += n;
                },
            },
        };
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    子组件:

    <template>
      <div>
        <div class="title">child组件div>
        <br />
        <div>{{ title }}--{{ age }}div>
        <br />
        <button @click="addAge">+++++button>
      div>
    template>
    
    <script>
    export default {
      props: {
        title: {
          // 接收的数据类型
          type: String,
          // 直接给值 [基础类型] | 回调函数 [基础类型和引用类型都可以,引用类型设置默认值必须是此方案]
          default: "我是一个字符串",
        },
        // 自定义方法验证接收的数据
        age: {
          type: Number,
          default: () => 10,
          // 验证操作
          validator: (value) => {
            if (value > 90) {
              // 返回一个警告
              return false;
            }
            return true;
          },
        },
        setAge: Function,
      },
      methods: {
        addAge() {
          this.setAge(2);
        },
      },
    };
    script>
    
    <style lang="scss" scoped>
    .title {
      color: red;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    在这里插入图片描述

    方法1实现:

    子组件:

    <template>
      <div>
        <div class="title">child组件div>
        <br />
        <div>{{ title }}--{{ age }}div>
        <br />
        <button @click="addAge">+++++button>
      div>
    template>
    
    <script>
    export default {
      props: {
        title: {
          // 接收的数据类型
          type: String,
          // 直接给值 [基础类型] | 回调函数 [基础类型和引用类型都可以,引用类型设置默认值必须是此方案]
          default: "我是一个字符串",
        },
        // 自定义方法验证接收的数据
        age: {
          type: Number,
          default: () => 10,
          // 验证操作
          validator: (value) => {
            if (value > 200) {
              // 返回一个警告
              return false;
            }
            return true;
          },
        },
        setAge: Function,
      },
      methods: {
        addAge() {
          // 通过给当前的组件定义一个自定义的事情,完成子向父
          // 参数1:自定义事件的名称,参数2以后,它是传过去的数据
          // this.$emit('onSetAge',......参数)
          this.$emit("onSetAge", 10);
        },
      },
    };
    script>
    
    <style lang="scss" scoped>
    .title {
      color: red;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        
        <child :title="title" :age="age" @onSetAge="setAge" />
      div>
    template>
    
    <script>
    import child from "./components/child.vue";
    
    export default {
      components: {
        child,
      },
      data() {
        return {
          title: "我是一个显示内容",
          age: 80,
        };
      },
      methods: {
        setAge(n = 1) {
          this.age += n;
        },
      },
    };
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    3. 兄弟组件间传值

    概述:

    兄弟间组件传值,通过公共的父组件来进行。这种方式使得两个兄弟组件共用的数据得到提升,即状态提升。

    子组件通过修改父组件中自己和兄弟的公共数据,来和自己的兄弟组件传值。

    示例:

    子组件1:

    <template>
      <div>
        <h3>child1 -- {{ age }}h3>
        <button @click="$emit('onAddAge', 1)">++++button>
      div>
    template>
    
    <script>
    export default {
      props: ["age"],
    };
    script>
    
    <style lang="scss" scoped>
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    子组件2:

    <template>
      <div>
        <h3>child2 -- {{ age }}h3>
      div>
    template>
    
    <script>
    export default {
      props: ["age"],
    };
    script>
    
    <style lang="scss" scoped>
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        <child1 :age="age" @onAddAge="addAge" />
        <child2 :age="age" />
      div>
    template>
    
    <script>
    import child1 from "./components/child1.vue";
    import child2 from "./components/child2.vue";
    
    export default {
      components: {
        child1,
        child2,
      },
      data() {
        return {
          age: 80,
        };
      },
      methods: {
        addAge(n = 1) {
          this.age += n;
        },
      },
    };
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    4. 事件总线

    概述:

    兄第组件间通过状态提升的方式来进行传值,适用于父子场景中,一旦涉及到子孙场景,状态提升的操作就变得很复杂,这时候我们就要用到 Vue2 中给我们提供的事件总线来处理。

    什么是事件总线?

    非父子组件或更多层级间组件间传值,在Vue中通过单独的事件中心来管理组件间的传值。

    它相当于一个全局的仓库,任何组件都可以去这个仓库里获取事件,它就类似沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行的通知其他组件来进行通信。

    简单来说就是,假设现在有一个组件 a 往全局仓库中塞数据,另一个组件 b 只要订阅了全局仓库,就可以收到更新的数据。

    事件总线只能进行通知,不能进行数据的存储功能。

    在这里插入图片描述

    注意:实现事件总线的前提条件是,必须先订阅和发布

    语法:

    • 建立统一的事件中心:const bus = new Vue()
    • 传递数据方,通过一个事件触发:bus.$emit(方法名,传递的数据)
    • 接收数据方,在生命周期函数中,通过bus.$on(方法名,(参数)=>{})来监听
    • 销毁事件,在接受数据方,通过bus.$off(方法名)销毁,销毁之后无法监听数据

    示例:

    建立统一的事件中心(即全局对象)可以在主 js 文件中写入如下代码:

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    // 事件总线  --- 是当前文件的私有变量
    // 因为所有组件对象都能看到 Vue 原型对象上的属性和方法,所以我们可以在Vue的原型对象上通过设定一个eventBus对象,
    // Vue.prototype.bus = new Vue(),此时所有的组件对象都能看到eventBus属性对象。
    const eventBus = new Vue()
    Vue.prototype.$eventBus = eventBus
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    也可以使用插件的方式,建立全局对象:

    新建一个 bus.js 文件:

    export default Vue => {
      Vue.prototype.$eventBus = new Vue()
    }
    
    • 1
    • 2
    • 3

    在 main.js 中导入:

    import Vue from 'vue'
    import App from './App.vue'
    import bus from './plugin/bus'
    
    Vue.config.productionTip = false
    Vue.use(bus)
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        <child1 :age="age" />
        <child2 :age="age" />
      div>
    template>
    
    <script>
    import child1 from "./components/child1.vue";
    import child2 from "./components/child2.vue";
    
    export default {
      components: {
        child1,
        child2,
      },
      data() {
        return {
          age: 80,
        };
      },
      // 让父组件也订阅子组件的频道,作为介质向子组件2传递数据
      created() {
        this.$eventBus.$on("age", (value) => (this.age += value));
      },
    
      // 在订阅的地方都要销毁,相当于关闭频道
      beforeDestroy() {
        this.$eventBus.$off("age");
      },
    };
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    子组件1(发布者):

    <template>
      <div>
        <h3>child1 -- {{ age }}h3>
        <button @click="setAge">+++++button>
      div>
    template>
    
    <script>
    export default {
      props: ["age"],
      methods: {
        setAge() {
          // 传递数据方
          // 这里的作用是,往全局对象中塞数据
          // 参数1:频道名称,不能重复
          // 参数2-N,传过去的数据
          this.$eventBus.$emit("age", 10);
        },
      },
    };
    script>
    
    <style lang="scss" scoped>
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    子组件2(订阅者):

    <template>
      <div>
        <h3>child2 -- {{ age }}h3>
      div>
    template>
    
    <script>
    export default {
      props: ["age"],
      // 接收数据方
      // 这里相当于子组件2订阅了 age 频道,可以接收到更新后的数据
      created() {
        this.$eventBus.$on("age", (value) => {
          console.log(value);
        });
      },
      beforeDestroy() {
        this.$eventBus.$off("age");
      }
    };
    script>
    
    <style lang="scss" scoped>
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    5. Ref

    概述:

    ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。

    ref 它不但可以实现组件通信,而且它还可以获取dom对象。

    使用ref来获取普通元素的dom对象:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        
        
        <div ref="username">张三div>
        <button @click="getUsernameDom">获取张三dombutton>
      div>
    template>
    
    <script>
    export default {
      components: {
    
      },
      data() {
        return {
    
        }
      },
      methods: {
        getUsernameDom() {
          // ref 获取dom对象
          console.log(this.$refs['username'].innerHTML)
        }
      }
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    ref 获取的 dom 列表并不是真实的 dom,因为获取 dom 是同步的,而视图渲染是异步的。我们需要用到$nextTick,该方法用于获取最新的dom的方法 等待视图渲染完毕后才触发执行,得到真实dom。

    ref 绑定到自定义组件:

    父组件:

    <template>
      <div>
        <h3 class="title">App组件 -- {{ ptitle }}h3>
        <hr />
        
        <child ref="childRef" />
        <button @click="getChild">父获取child组件中的数据button>
      div>
    template>
    
    <script>
    import child from './components/child.vue'
    export default {
      components: {
        child
      },
      data() {
        return {
          age: 100,
          ptitle: ''
        }
      },
      methods: {
        getChild() {
          // this.$refs.childRef.title = 'aaaaa'
          // this.ptitle = this.$refs.childRef.title
          this.ptitle = this.$refs.childRef.setTitle('afewfewfew')
        }
      },
      // 写在 mounted 中也可以实现
    //   mounted(){
    //     // console.log(this.$refs.childRef?.title)
    //     this.ptitle = this.$refs.childRef.title
    //   }
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    子组件:

    <template>
      <div>
        <h3>child组件h3>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          title: '我是child组件中的数据'
        }
      },
      methods: {
        setTitle(title) {
          this.title = title+'#####3'
          return this.title
        }
      }
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    6. root/parent/children

    概述:

    获取父组件对象或子组件对象集合。

    三个方法:

    this.$root
    this.$parent
    this.$children
    
    • 1
    • 2
    • 3

    示例:

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <button @click="getChild">父获取child组件中的数据button>
        <hr />
        <child />
      div>
    template>
    
    <script>
    import child from './components/child.vue'
    export default {
      components: {
        child
      },
      data() {
        return {
          title: 'parent'
        }
      },
      methods: {
        getChild() {
          console.log(this.$root,"---父组件中获取");
          // console.log(this.$children);
          // 获取子元素中的数据
          // console.log(this.$children[0].title);
          // 如果有多个孩子
          this.$children.forEach(node => {
            // console.log(node?.title)
            // 短路运算
            console.log(node.title && node.title)
          })
        }
      }
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    子组件:

    <template>
      <div>
        <h3>child组件h3>
        <button @click="getParent">获取父组件中的数据button>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          title: '我是child组件中的数据'
        }
      },
      methods: {
        getParent() {
          // 获取到根上的元素(main.js),在任何层级都可以获取
          console.log(this.$root,"---子组件中获取")
          // 子组件获取父组件
          console.log(this.$parent.title)
        }
      }
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    7. provide/inject

    概述:

    provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

    这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

    比如我们现在想要封装一个组件,组件内层级很多,我们想在组件内实现很方便的通信,却又想要与外界隔绝,这时候就需要用到 provide/inject。

    父组件向子组件传值:

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        <child />
      div>
    template>
    
    <script>
    import child from "./components/child.vue";
    export default {
      components: {
        child,
      },
      data() {
        return {
          msg: 'app中的标题'
        };
      },
      // 发布,父组件的后代无论在哪个层级都能收到
      // 写法1:
      // provide: {
      //   title: "app中的标题",
      // },
      // 如果你要使用当前组件中的数据或方法,就需要把provide写成函数方式且返回一个对象
      // 写法2:
      provide() {
        return {
          title: this.msg,
        };
      },
      methods: {},
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    子组件:

    <template>
      <div>
        <h3>child组件 --- {{ title }}h3>
      div>
    template>
    
    <script>
    export default {
      // 注入
      // 数组方式接收  写的比较的多
      // inject: ['title'],
      // 对象方式接收
      inject: {
        title: {
          // 默认值
          default: () => '默认值'
        },
      },
      data() {
        return {};
      },
      methods: {},
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    provide 和 inject 绑定并不是可响应的,如果想要变成响应式的,可以在父组件中 provide 返回一个函数,并且在子组件中接收:

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <input v-model="msg" />
        <hr />
        <child />
      div>
    template>
    
    <script>
    import child from "./components/child.vue";
    export default {
      components: {
        child,
      },
      data() {
        return {
          msg: 'app中的标题'
        };
      provide() {
        return {
          title: () => this.msg
        };
      },
      methods: {},
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    子组件:

    <template>
      <div>
        <h3>child组件 --- {{ title() }}h3>
      div>
    template>
    
    <script>
    export default {
      // 对象方式接收
      inject: {
      title: {
        // 默认值
        default: () => () => "默认值",
      },
      },
      data() {
        return {};
      },
      methods: {},
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    8. $attrs/$listeners

    概述:

    $attrs 获取没有在 props 中定义的属性,把 props 没有接收到的属性进行接收

    $listeners 获取父组件给子组件自定义事件

    示例:

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        <child :msg="msg" uid="1" @setTitle="setTitle" />
      div>
    template>
    
    <script>
    import child from './components/child.vue'
    export default {
      components: {
        child
      },
      data() {
        return {
          msg: 'app中的标题'
        }
      },
      methods: {
        setTitle(title) {
          this.msg = title
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    子组件:

    <template>
      <div>
        <h3>child组件 --- {{ $attrs.msg }}h3>
        <button @click="setMsg">修改msgbutton>
      div>
    template>
    
    <script>
    export default {
      props: ['uid'],
      data() {
        return {}
      },
      methods: {
        setMsg() {
          // console.log(this.$listeners)
          this.$listeners.setTitle(Date.now())
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    在这里插入图片描述

    利用 attrs 来处理所以的自定义属性数据:

    简单来说,就是拿一个组件(数据层容器)包裹另一个组件(最终显示在页面上的组件),增强了组件能力。

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        <child :phone="phone" :uid="100" />
      div>
    template>
    
    <script>
    import child from './components/child.vue'
    export default {
      components: {
        child
      },
      data() {
        return {
          phone: '1323125125'
        }
      },
      methods: {}
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    子组件(数据层容器,进行数据包装和处理):

    <template>
      <div>
        <h3>child组件h3>
        <showphone :attrs="attrs" />
      div>
    template>
    
    <script>
    import showphone from './showphone.vue'
    export default {
      components: {
        // child 组件不直接显示数据,而是将数据进行包装处理后,交给自己的子组件 showphone 来显示
        // 这时的 child 相当于一个数据层容器,包裹了 showphone 进行了相关的数据处理
        showphone
      },
      data() {
        return {
          attrs: {}
        }
      },
      created() {
        this.attrs = { ...this.$attrs, phone: 'abc ---' + this.$attrs.phone }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    子组件的子组件(最终显示在页面数据的组件):

    <template>
      <div>
        <h3>showphone显示手机号码 --- {{ attrs.phone }}h3>
      div>
    template>
    
    <script>
    export default {
      props: ['attrs']
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    9. v-model绑定到自定义组件中

    默认用法:

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        
        
        <hr />
        
         
        
        <child v-model="title" />
      div>
    template>
    
    <script>
    import child from './components/child.vue'
    export default {
      components: {
        child
      },
      data() {
        return {
          title: '我是父组件的title'
        }
      },
      // v-model相当于写有这个方法
      // methods: {
      //   setTitle(title) {
      //     this.title = title
      //   }
      // }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    子组件:

    <template>
      <div>
        
        <h3>child组件 -- {{ value }}h3>
        
        <button @click="$emit('input', Date.now())">修改value数据button>
      div>
    template>
    
    <script>
    export default {
      // 默认的
      props: ['value'],
      data() {
        return {};
      },
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    除了使用默认的用法,还可以自定义属性名称和事件名称:

    只需要修改子组件:

    <template>
      <div>
        
        { value }} -->
        <h3>child组件 -- {{ title }}h3>
        
        
        <button @click="$emit('change', Date.now())">修改value数据button>
      div>
    template>
    
    <script>
    export default {
      // 默认的
      // props: ['value'],
      props: ["title"],
      model: {
        // 修改v-model中的绑定的属性名称,默认为value
        prop: "title",
        // 修改v-model它的自定义事件的名称,默认为input
        event: "change",
      },
      data() {
        return {};
      },
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    10. sync同步动态属性数据

    上文说到 props 是单向数据流,子组件不能修改父组件的数据,但是加上 sync 修饰符就可以实现修改 。

    父组件:

    <template>
      <div>
        <h3 class="title">App组件h3>
        <hr />
        
        <child :title.sync="title" />
      div>
    template>
    
    <script>
    import child from './components/child.vue'
    export default {
      components: {
        child
      },
      data() {
        return {
          title: '我是父组件的title'
        }
      },
      methods: {}
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    子组件:

    <template>
      <div>
        <h3>child组件 -- {{ title }}h3>
        <button @click="setTitle">修改Titlebutton>
      div>
    template>
    
    <script>
    export default {
      props: ['title'],
      data() {
        return {}
      },
      methods: {
        setTitle() {
          // 这里的update事件是固定写法
          this.$emit('update:title', Date.now())
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    11. localStorage / sessionStorage

    这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。

    通过window.localStorage.getItem(key)获取数据

    通过window.localStorage.setItem(key,value) 存储数据

    注意用JSON.parse() / JSON.stringify() 做数据格式转换

    localStorage / sessionStorage可以结合vuex,实现数据的持久保存,同时使用vuex解决数据和状态混乱问题。

  • 相关阅读:
    IC - 基础知识 - SOC与MCU
    Android Studio实现课程表应用,美观又实用(Kotlin版本)
    撸视频号收益这个副业靠谱吗?
    美式发音速成笔记
    十一、DHT11 温湿度检测(OLED显示)
    2、音视频基础
    C++-头文件书写规范(二):头文件中的保护措施【#ifndef #define...#endif 】【防止多个源文件同时包含同一个头文件时产生的声明冲突】
    L2-015 互评成绩
    使用 React 和 Django Channels 构建聊天应用程序
    Github每日精选(第10期):终端操作录制工具asciinema
  • 原文地址:https://blog.csdn.net/weixin_45605541/article/details/126771989