• Vue2与Vue3的组件通讯对比


    Vue2

    父传子

    父传子比较简单, 主要通过以下步骤实现

    1. 父在template中为子绑定属性

      <Child :childData='pMsg'/>
      <!-- 也可以写死 -->
      <Child childData='123'/>
      
    2. 子用props接收数据, props的值可以是数组或对象

      props: ["childData"]
      
    3. 子在template中或其他地方任意使用接受到的数据

      <h2>我得到了{{childData}}</h2>
      

    列出完整例子:

    <!--@html-start-->
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>title</title>
        </style>
      </head>
      <body>
        <div id="app">{{ message }}</div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
      </body>
    </html>
    
    <!--@html-end-->
    
    <!--@css-start-->
    fieldset {
    	margin-top: 30px;
    }
    <!--@css-end-->
    
    <!--@javascript-start-->
    Vue.component("Parent", {
      data() {
        return {
          pMsg: "小楼昨夜又东风",
        };
      },
      //步骤一
      template: `<div><fieldset><legend>父组件</legend><input type="text" v-model="pMsg"/><Child :childData='pMsg'/></fieldset></div>`,
    });
    Vue.component("Child", {
      //步骤三
      template: `<div><fieldset><legend>子组件</legend>来自父组件的数据: {{ childData }}</fieldset></div>`,
      //步骤二
      props: ["childData"],
    });
    var vm = new Vue({
      el: "#app",
      data() {
        return {
          msg: "往input中输入东西试试",
        };
      },
      template: `<div><fieldset><legend>App组件</legend>{{ msg }}<Parent/></fieldset></div>`,
    });
    <!--@javascript-end-->
    
    

    子传父

    1. 父组件中为子组件绑定一个自定义事件
      <h2> <Child @childHandler="childHandler" /></h2>`
      
    2. 父组件中为自定义事件写函数,形参为要接收的值,假如要加到this中的话,最好在data中预留一个key
      methods: {
      	childHandler(val) {
      		this.ChildData = val
      	}
      }
      
    3. 子组件中绑定一个原生事件
      @input="change(data)"
      
      再在方法中使用$emit调用父组件中的方法
      this.$emit("childHandler", val)
      
      触发父组件中的自定义事件

      $emit: 触发当前实例上的事件。附加参数都会传给监听器回调

    完整例子:

    <!--@html-start-->
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>title</title>
      </head>
      <body>
        <div id="app">{{ message }}</div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
      </body>
    </html>
    
    <!--@html-end-->
    <!--@css-start-->
    fieldset {
    	margin-top: 30px;
    }
    <!--@css-end-->
    <!--@javascript-start-->
    Vue.component("Parent", {
      data() {
        return {
          ChildData: "",
        };
      },
      //步骤一
      template: `<div><fieldset><legend>父组件</legend><p>来自子组件的数据: {{ ChildData }}</p><Child @childHandler="childHandler" /></fieldset></div>`,
      // 步骤二
      methods: {
        // 处理从子组件中获取的数据
        childHandler(val) {
          this.ChildData = val;
        },
      },
    });
    Vue.component("Child", {
      data() {
        return {
          data: "故国不堪回首月明中",
        };
      },
      //步骤三
      template: `<div><fieldset><legend>子组件</legend><input type="text" v-model="data" @input="change(data)" /></fieldset></div>`,
      methods: {
        // 调用$emit方法
        change(val) {
          this.$emit("childHandler", val);
        },
      },
    });
    var vm = new Vue({
      el: "#app",
      data() {
        return {
          msg: "在input中输入东西试试",
        };
      },
      template: `<div><fieldset><legend>App组件</legend>{{msg}}</h1><Parent/></fieldset></div>`,
    });
    
    <!--@javascript-end-->
    
    

    父传孙

    父组件里使用provide, 子组件里使用inject
    完整例子

    <!--@html-start-->
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>title</title>
      </head>
      <body>
        <div id="app">{{ message }}</div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
      </body>
    </html>
    <!--@html-end-->
    
    <!--@javascript-start-->
    Vue.component("Parent", {
      data() {
        return { data: "小楼昨夜又东风" };
      },
      template: `<div><fieldset><legend>父组件</legend><p>父组件数据: {{ data }}</p><Child /></fieldset></div>`,
      // 步骤一
      provide() {
        return {
          data: this.data,
        };
      },
    });
    Vue.component("Child", {
      template: `<div><fieldset><legend>子组件</legend><GrandSon /></fieldset></div>`,
    });
    Vue.component("GrandSon", {
      // 步骤二
      // 接收祖辈的数据 data
      inject: ["data"],
      data() {
        return {
          // 通过this.x取值
          parentData: this.data,
        };
      },
      template: `<div><fieldset><legend>孙组件</legend><p>祖辈的数据: {{ parentData }}</p></fieldset></div>`,
    });
    var vm = new Vue({
      el: "#app",
      data() {
        return {
          msg: "观察组件的数据",
        };
      },
      template: `<div><fieldset><legend>App组件</legend><p>{{ msg }}</p><Parent/></fieldset></div>`,
    });
    
    <!--@javascript-end-->
    <!--@css-start-->
    fieldset {
    	margin-top: 30px;
    }
    <!--@css-end-->
    

    注意, 这种方法传值不是响应数据
    你可以把数据变为object类型, 让其可以同步修改

    兄弟之间互传

    1. 在Vue的原型对象向上添加一个属性叫$bus
      该属性是一个Vue实例对象
    2. 发送端, 调用this.$bus.$emit
    3. 接收端, 监听对应事件, 处理数据

    完整例子:

    <!--@html-start-->
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>title</title>
      </head>
      <body>
        <div id="app">{{ message }}</div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
      </body>
    </html>
    <!--@html-end-->
    <!--@javascript-start-->
    // 步骤一 添加$bus属性
    Vue.prototype.$bus = new Vue();
    
    Vue.component("Child1", {
      data() {
        return { data: "小楼昨夜又东风" };
      },
      methods: {
        update() {
          // 步骤二 使用$emit触发自定义事件, 传入数据
          this.$bus.$emit("handlerData", this.data);
        },
      },
      template: `<div><fieldset><legend>子组件</legend><p>子组件发送的数据:  <input type="text" v-model="data" @input="update()"/></p></fieldset></div>`,
    });
    Vue.component("Child2", {
      data() {
        return {
          data: "",
        };
      },
      mounted() {
        // 步骤三 处理传过来的数据
        this.$bus.$on("handlerData", (val) => {
          this.data = val;
        });
      },
      template: `<div><fieldset><legend>子组件</legend><p>子组件接收的数据: {{ data }}</p></fieldset></div>`
    });
    var vm = new Vue({
      el: "#app",
      data() {
        return {
          msg: "往input中输入数据试试",
        };
      },
      template: `<div><fieldset><legend>App组件</legend><p>{{msg}}</p><Child1 /> <Child2 /></fieldset></div>`,
    });
    <!--@javascript-end-->
    <!--@css-start-->
    fieldset {
    	margin-top: 30px;
    }
    <!--@css-end-->
    

    Vue3

    由于vue3vue2的选项变为了组合API, 而且把datamethods集合到了setup中, 故而使用起来有所区别, 但也大差不差

    父传子

    1. 父组件使用refreactive将数据变为响应数据
    2. 子组件使用props接收

      关于props见: props

    3. 要在setup中使用, 使用如下方法:
      props: ["data"],
      setup(props, context) {
        props.data
      }
      

    完整例子

    <!--@html-start-->
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>title</title>
      </head>
      <body>
        <div id="app">
          <fieldset>
            <legend>app组件</legend>
            {{ data }}
            <!-- 使用组件 -->
            <Parent />
          </fieldset>
        </div>
    
        <script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script>
      </body>
    </html>
    <!--@html-end-->
    <!--@javascript-start-->
    const AttributeBindingApp = {
      name: "App",
      setup() {
        const data = "往input中输入东西试试";
        return {
          data,
        };
      },
    };
    const app = Vue.createApp(AttributeBindingApp);
    app.component("Parent", {
      setup() {
        // 变为响应数据
        const parentData = Vue.ref("故国不堪回首月明中");
        return {
          parentData,
        };
      },
      template: `<fieldset><legend>父组件</legend> <input type="text" v-model="parentData" /> <Child :parentData="parentData" /></fieldset>`,
    });
    app.component("Child", {
      props: ["parentData"],
      setup() {
        const childData = "childData";
    
        return {
          childData,
        };
      },
      template: `<fieldset><legend>子组件</legend>{{ parentData }}</fieldset>`,
    });
    app.mount("#app");
    
    <!--@javascript-end-->
    <!--@css-start-->
    fieldset {
    	margin-top: 30px;
    }
    <!--@css-end-->
    

    子传父

    1. 父组件中定义接收数据的方法
    2. template中为子组件绑定自定义事件
    3. 在子组件中触发自定义事件, 执行context.emit方法
    4. 传给父组件使用

    总的来说, 原理与Vue2差不多, 但由于要在setup中获取值, 故要使用参数接收

    <!--@html-start-->
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>title</title>
      </head>
      <body>
        <div id="app">
          <fieldset>
            <legend>app组件</legend>
            {{ data }}
            <!-- 使用组件 -->
            <Parent />
          </fieldset>
        </div>
    
        <script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script>
      </body>
    </html>
    <!--@html-end-->
    <!--@javascript-start-->
    const AttributeBindingApp = {
      name: "App",
      setup() {
        const data = "往input中输入东西试试";
        return {
          data,
        };
      },
    };
    const app = Vue.createApp(AttributeBindingApp);
    app.component("Parent", {
      setup(props, context) {
        const childData = Vue.ref("");
        // 步骤一 定义处理接收数据的方法
        const receive = (e) => {
          // 处理从子组件中传来的数据
    
          childData.value = e;
        };
        return {
          receive,
          childData,
        };
      },
      // 步骤二 自定义事件 触发处理接收数据的方法
      template: `<fieldset><legend>父组件</legend><p>子组件中的数据: {{ childData }}</p><Child @inputText="receive" /></fieldset>`,
    });
    app.component("Child", {
      props: ["parentData"],
    
      setup(props, context) {
        const data = Vue.ref("小楼昨夜又东风");
        // 步骤四 调用context.emit
        const toParent = () => {
          // input时调用
          // 调用inputText事件
    
          context.emit("inputText", data.value);
        };
        return {
          data,
          toParent,
        };
      },
      // 步骤三 触发事件
      template: `<fieldset><legend>子组件</legend><input type="text" @input="toParent" v-model="data" /></fieldset>`,
    });
    app.mount("#app");
    <!--@javascript-end-->
    <!--@css-start-->
    fieldset {
    	margin-top: 30px;
    }
    <!--@css-end-->
    

    父传孙

    和vue2一样, 同样使用provideinject
    但不同的是, 我们可以使用refreactive将数据转换为响应式数据

    <!--@html-start-->
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>title</title>
      </head>
      <body>
        <div id="app">
          <fieldset>
            <legend>app组件</legend>
            {{ data }}
            <!-- 使用组件 -->
            <Parent />
          </fieldset>
        </div>
    
        <script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script>
      </body>
    </html>
    
    <!--@html-end-->
    <!--@javascript-start-->
    const AttributeBindingApp = {
      name: "App",
      setup() {
        const data = "往两个input中都输入试试";
        return {
          data,
        };
      },
    };
    const app = Vue.createApp(AttributeBindingApp);
    app.component("Parent", {
      setup() {
        // 响应的数据
        const data = Vue.ref("");
        // 步骤一 使用provide
        // 把data 标记为 "parentData"
        Vue.provide("parentData", data);
        return {
          data,
        };
      },
      template: `<fieldset><legend>父组件</legend>从子孙辈中获取的数据: <input type="text" v-model="data" /> <Child /></fieldset>`,
    });
    app.component("Child", {
      template: `<fieldset><legend>子组件</legend><GrandSon /></fieldset>`,
    });
    app.component("GrandSon", {
      setup() {
        // 步骤二 接收数据
        // 接收 parentData
        const data = Vue.inject("parentData");
        return {
          data,
        };
      },
      template: `<fieldset><legend>孙组件</legend><p>从父辈中获取的数据: <input type="text" v-model="data" /></p></fieldset>`,
    });
    app.mount("#app");
    
    <!--@javascript-end-->
    
    <!--@css-start-->
    fieldset {
    	margin-top: 30px;
    }
    <!--@css-end-->
    
    

    本文来自博客园,作者:403·Forbidden,转载请注明原文链接:https://www.cnblogs.com/lczmx/p/15708222.html

  • 相关阅读:
    后序非递归遍历二叉树的应用
    关于驰骋工作流程引擎,工作流程管理系统演示与学习环境发布的通知。
    驰骋工作流程引擎,ccflow,如何把子线程的数据汇总到合流节点表单中去?
    关于取消ccflow abc 级别用户与开放表单设计器源代码的通知
    驰骋工作流程引擎问题解答,武汉朋友。
    ccform 单据打印的规则调整与新增功能发布说明
    发几个傻瓜表单设计器预览图片,以方便大家学习.
    关于工作流程管理系统中的现有版本自由表单设计器的停止升级与新版本将要发布的声明.
    ccflow向流程开始节点表单传输数据方法大全
    利用开源的驰骋工作流程引擎,处理的集团公司流程应用案例之一.
  • 原文地址:https://www.cnblogs.com/lczmx/p/15708222.html
Copyright © 2020-2023  润新知