美文网首页
7天深入Vue - vue组件之间的通讯与插槽(一)

7天深入Vue - vue组件之间的通讯与插槽(一)

作者: 申_9a33 | 来源:发表于2021-02-11 15:24 被阅读0次

    常用组件之间的通讯

    1.props

    • vue 基础父子组件通讯
    • 数组形式 子组件定义props:['title', 'likes'] ,父组件 :title="title" :likes="likes"
    • 对象形式
    props:{
     title:{
       type:String, // 类型 String,Number,Boolean,Array,Object,Date,Function,Symbol
       default:"",  // 默认值 为引用类型时,需要为构造函数
       requred:true  // 是否必填
     }
    }
    

    注意props 属性忽略大小写,可以使用‘-’来替换驼峰命名


    2.eventBus

    • 构造
      • const bus = new Vue()
    • 发送事件
      • bus.$emint("testEvent","hello")
    • 监听事件
      • bus.$on("testEvent",handle)
    • 移除事件
      • bus.$off("testEvent",handle)
    • 实现一个eventBus (其实原理就是发布者订阅者模式)
    class EventBus {
      private busMap: Map<string, Array<Function>>;
      constructor() {
        this.busMap = new Map()
      }
    
      $emit(name: string, arg: any) {
        const list = this.busMap.get(name)
        if (!Array.isArray(list)) {
          return;
        }
    
        for (const fn of list) {
          try {
            if (typeof fn != "function") {
              throw new Error("")
            }
    
            fn(arg);
          } catch (error) {
            console.error(error)
          }
        }
    
      }
    
      $on(name: string, cb: Function) {
        if (typeof name !== "string" || typeof cb !== "function") {
          throw new Error("参数类型错误")
        }
    
        let list = this.busMap.get(name)
        if (!list) {
          list = []
          this.busMap.set(name, list)
        }
    
        list.push(cb)
      }
    
      $off(name: string, cb: Function) {
        const list = this.busMap.get(name)
        if (!Array.isArray(list)) {
          return
        }
    
        const index = list.findIndex(fn => cb === fn)
        if (index !== -1) {
          list.splice(index, 1)
        }
      }
    }
    
    const bus = new EventBus()
    

    3.Vuex

    • 3.1 state 数据仓库
      const state = {
        data:""
      }
    
    • 3.2 mutations 同步修改state的值
      const mutations = {
        changeData(state,v){
          state.data = v
        }
      }
    
    • 3.2 actions 异步修改state的值
      const actions = {
          fetchData({commit},arg){
              /**...**/
              /**异步代码 的回调 start**/
              commit("changeData",arg)
             /**异步代码 的回调 end**/
          }
      }
    
    • 3.3 getters 计算数据 (可以用来对数据进行过滤和拼接)
      const getters = {
          getData(state){
              return "pre"+state.data 
          }
      }
    
    • 3.4 modules 模块化
      export default new Vuex.Store({
      modules: {
         dataStore:{
            state ,
            mutations,
            actions,
            getters
         }
      }
    })
    
    • 3.5使用
      import { mapGetters, mapActions, mapMutations } from "vuex";
      export default {
        computed:{
          ...mapGetters({
            data:getters
          })
        },
        methods:{
          ...mapActions([
            "fetchData"
          ]),
          ...mapMutations([
            "changeData"
          ])
        }
      }
    

    4.$parent (可以用来给两个子组件进行通讯,发布订阅模式)

      /**子组件1**/
      this.$parent.$emit("event-from-children1",value)
    

    /**子组件2**/
      this.$parent.$on("event-from-children1",v=>{
        console.log(v)
      })
    

    5.$children (父组件可以直接访问子组件的方法和数据)

    this.$children[0].xx() // 访问子组件0的方法 注意存在异步组件时,组件顺序不可知
    

    6.$root (特殊的parent,使用一样 )


    7.$refs (可以拿到指定的children,可以访问子组件的实例)

    /**标签**/
    <from ref="from"/>
    
    /**调用**/
     this.$refs["from"].xx()
    

    8.provide/inject (依赖注入)

    /**父组件**/
    
      provide() {
        return {
          from: this, // 注入自己,子组件通过from 拿自己想拿的数据
        };
      },
    
    /**任意子组件**/
    
    inject: ["from"],
    /**or**/
    inject:{
      par:{from:"from"}
    }
    

    9.$attrs (用于父组件直接给子组件传值,class 和 style 的其他数据会默认转移到子组件的最外层标签之上)

    inheritAttrs: false 可以禁止转移到子组件的最外层标签

      /**父组件**/
    <Item label="用户名" prop='username'>
    
    /**item 组件**/
    console.log(this.$attrs.label)
    console.log(this.$attrs.prop)
    

    10.$listeners (子组件不处理的事件,传递给父组件处理,或者说父组件传递给子组件处理函数)

        <div id="app">
          <child1
            :p-child1="child1"
            :p-child2="child2"
            :p-child-attrs="1231"
            v-on:test1="onTest1"
            v-on:test2="onTest2">
          </child1>
        </div>
       <script>
          Vue.component("Child1", {
            inheritAttrs: true,
            props: ["pChild1"],
            template: `
            <div class="child-1">
            <p>in child1:</p>
            <p>props: {{pChild1}}</p>
            <p>$attrs: {{this.$attrs}}</p>
            <hr>
            <child2 v-bind="$attrs" v-on="$listeners"></child2></div>`,
            mounted: function() {
              this.$emit("test1");
            }
          });
          Vue.component("Child2", {
            inheritAttrs: true,
            props: ["pChild2"],
            template: `
            <div class="child-2">
            <p>in child->child2:</p>
            <p>props: {{pChild2}}</p>
            <p>$attrs: {{this.$attrs}}</p>
              <button @click="$emit('test2','按钮点击')">触发事件</button>
            <hr> </div>`,
            mounted: function() {
              this.$emit("test2");
            }
          });
          const app = new Vue({
            el: "#app",
            data: {
              child1: "pChild1的值",
              child2: "pChild2的值"
            },
            methods: {
              onTest1() {
                console.log("test1 running...");
              },
             onTest2(value) {
                console.log("test2 running..." + value);
              }
            }
          });
        </script>
    

    插槽

    /**子组件定义插槽**/
    
    /*具名插槽*/
    <slot name="header"></slot>
    
    /*匿名插槽*/
    <slot></slot>
    
    /*作用域插槽*/
     <slot name="cell" :item="item" :index="index"></slot>
    
    /**父组件使用插槽**/
    /*具名插槽*/
    <template v-slot:header>...</template>
    
    /*匿名插槽*/
    <template>...</template>
    
    作用域插槽
     <template v-slot:cell="{ item, index }">...</template>
    

    相关文章

      网友评论

          本文标题:7天深入Vue - vue组件之间的通讯与插槽(一)

          本文链接:https://www.haomeiwen.com/subject/dwxrxltx.html