Vue 组件通信简单代码实现

前言:

      本片文章着重将组件通信的简单实现代码给大家呈现以下,希望对大家有所帮助

组件通信:

父组件 => 子组件:

属性props

//父页面
<template>
  <div id="app">
    <input type="text" v-model="text" @change="dataChange">
        <Children :msg="text"></Children>
  </div>
</template>

<script>
import Children from './components/组件传值/son'

export default {
  name: "app",
  components: {
    Children
  },
  data() {
    return {
      text: "父组件的值",
    };
  },
  methods: {
     dataChange(data) {
       this.msg = data
     }
  }
};
</script>
//子组件
<template>
  <div id="container"> {{msg}} </div>
</template>
<script>
export default {
  data() {
    return {};
  },
  props: {
    msg: String
  }
};
</script>

引用refs

//父页面
<template>
  <div id="app">
    <input type="text" v-model="text" @change="dataChange">
            <Children ref="msg"></Children>
  </div>
</template>

<script>
import Children from './components/组件传值/son'

export default {
  name: "app",
  components: {
    Children
  },
  data() {
    return {
      text: "父组件的值",
    };
  },
  methods: {
     dataChange(data) {
       this.$refs.msg.msg = data.target.value;
     }
  },
  mounted() {
    this.$refs.msg.msg = this.text;
  }
};
</script>
//子组件
<template>
  <div id="container"> {{msg}} </div>
</template>
<script>
export default {
  data() {
    return {};
  },
  props: {
    msg: String
  }
};
</script>

子组件 => 父组件:自定义事件

//父组件
<template>
  <div id="app">
    <p>我是父组件</p>
    <ChildrenEmit :isShow="show" @hidechild="hidechild"></ChildrenEmit>
    <button @click="show=true">显示子组件</button>
  </div>
</template>

<script>
import ChildrenEmit from './components/组件传值/父子组件通信 emit/son'
export default {
  name: "app",
  components: {
    ChildrenEmit
  },
  data() {
    return {
      show: false
    };
  },
  methods: {
    hidechild: function (data) {
      this.show = data;
    }
  }
};
</script>
//子组件
<template>
  <div>
    <h2 v-show="isShow">我是子组件</h2>
    <button @click="hideMyself()">隐藏子组件</button>
  </div>
</template>

<script>
export default {
  name: "child",
  props: {
    isShow: Boolean
  },
  methods: {
    hideMyself: function () {
      this.$emit('hidechild', false);
    }
  }
}
</script>

兄弟组件:通过共同祖辈组件

通过共同的祖辈组件搭桥,$parent或$root。

//父组件
<template>
  <div id="app">
    <son :message="sisterText"></son>
    <sister :message="sonText"></sister>
  </div>
</template>

<script>
import son from './components/组件传值/兄弟组件通信/son'
import sister from './components/组件传值/兄弟组件通信/sister'
export default {
  name: "app",
  components: {
    son,
    sister
  },
  data() {
    return {
      sonText: '',
      sisterText: ''
    };
  },
  methods: {
    sendMessage: function (data, who) {
      if (who == '姐姐') {
        this.sisterText = data;
      } else {
        this.sonText = data;
      }
    }
  }
};
</script>
//子组件 姐姐
<template>
  <div>
    <h2>我是姐姐组件</h2>
    <h3>{{message}}</h3>
    <button @click="sendMessage()">给弟弟发消息</button>
  </div>
</template>

<script>
export default {
  name: "sister",
  props: {
    message: String
  },
  methods: {
    sendMessage: function () {
      this.$parent.sendMessage('弟弟该吃饭了', '姐姐');
    }
  }
}
</script>
//子组件 弟弟
<template>
  <div>
    <h2>我是弟弟组件</h2>
    <h3>{{message}}</h3>
    <button @click="sendMessage()">给姐姐发消息</button>
  </div>
</template>

<script>
export default {
  name: "son",
  props: {
    message: String
  },
  methods: {
    sendMessage: function () {
      this.$parent.sendMessage('姐姐该吃饭了', '弟弟');
    }
  }
}
</script>

祖先和后代之间

provide/inject:能够实现祖先给后代传值

// ancestor 祖辈
<template>
  <div id="app">
    <grandSon></grandSon>
  </div>
</template>

<script>
import grandSon from './components/组件传值/祖先后代传值/grandSon'

export default {
  name: "app",
  components: {
    grandSon
  },
  data() {
    return {
      message: '我是爷爷组件传过来的数据'
    };
  },
  provide() {
    return {
      message: this.message
    }
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
//我是孙子组件
<template>
  <div>
    <h2>我是孙子组件</h2>
    <h3>{{message}}</h3>
  </div>
</template>

<script>
export default {
  name: "son",
  inject: ['message']
}
</script>

注: provide 和 inject 主要为高级插件/组价库提供,不推荐直接在应用程序编写,我们更多会在开源组件库中见到

dispatch:后代给祖先传值

// 祖先
<template>
  <div id="app">
    <grandSon></grandSon>
  </div>
</template>

<script>
import grandSon from './components/组件传值/后代祖先传值/grandSon'

export default {
  name: "app",
  components: {
    grandSon
  },
  mounted() {
    this.$on('hello', (data) => {
      console.log(data);
    });
  },
};
</script>
<template>
  <div>
    <h2 @click="dispatch('hello', 'hello,world')">我是孙子组件</h2>
  </div>
</template>

<script>
export default {
  name: "son",
  methods: {
    // 定义一个dispatch方法,指定要派发事件名称和数据
    dispatch(eventName, data) {
      let parent = this.$parent
      // 只要还存在父元素就继续往上查找
      while (parent) {
        // 父元素用$emit触发
        parent.$emit(eventName, data)
        // 递归查找父元素
        parent = parent.$parent
      }
    }
  },
}
</script>

任意两个组件之间:事件总线 或 vuex

事件总线:创建一个Bus类负责事件派发、监听和回调管理

// Bus:事件派发、监听和回调管理
class Bus{
  constructor(){
      // {
      // eventName1:[fn1,fn2],
      // eventName2:[fn3,fn4],
      // }
     this.callbacks = {}
  }
  $on(name, fn){
      this.callbacks[name] = this.callbacks[name] || []
      this.callbacks[name].push(fn)
  }
$emit(name, args){
    if(this.callbacks[name]){
    this.callbacks[name].forEach(cb => cb(args))
  }
}
//父页面
<template>
  <div id="app">
    <son></son>
    <sister></sister>
  </div>
</template>

<script>

import son from './components/组件传值/任意两个组件传值/son'
import sister from './components/组件传值/任意两个组件传值/sister'

export default {
  name: "app",
  components: {
    son,
    sister,
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
//子页面 
<template>
  <div>
    <h2>我是姐姐组件</h2>
    <h3>{{message}}</h3>
    <button @click="sendToSonMessage()">给弟弟发消息</button>
  </div>
</template>

<script>
import Bus from './bus'
export default {
  name: "sister",
  methods: {
    sendToSonMessage: function () {
      Bus.$emit('sendToSonMessage', '弟弟该吃饭了');
    }
  },
  mounted() {
    Bus.$on('sendToSisterMessage', target => {
      this.message = target
      //注意:发送和监听的事件名称必须一致,target就是获取的数据,可以不写target。只要你喜欢叫什么都可以(当然了,这一定要符合形参变量的命名规范)
    })
  },
  beforeDestroy() {
    //清除事件总线eventBus
    Bus.$off('sendToSisterMessage')
  }
}
</script>
 
//子页面 
<template>
  <div>
    <h2>我是弟弟组件</h2>
    <h3>{{message}}</h3>
    <button @click="sendToSisterMessage()">给姐姐发消息</button>
  </div>
</template>

<script>
import Bus from './bus'
export default {
  name: "son",
  methods: {
    sendToSisterMessage: function () {
      Bus.$emit('sendToSisterMessage', '姐姐该吃饭了')
    }
  },
  mounted() {
    Bus.$on('sendToSonMessage', target => {
      this.message = target
      //注意:发送和监听的事件名称必须一致,target就是获取的数据,可以不写target。只要你喜欢叫什么都可以(当然了,这一定要符合形参变量的命名规范)
    })
  },
  beforeDestroy() {
    //清除事件总线eventBus
    Bus.$off('sendToSonMessage')
  }
}
</script>

注意:在实践中我们可以使用vue替代bus,因为它实现了相应功能

   vuex: 创建唯一的全局数据管理者store,通过它管理数据并通知组件状态更改


插槽

Vue 2.6.0之后采用全新v-slot语法取代之前的slot、slot-scope

匿名插槽

//匿名插槽组件
<template>
  <div>
    <h2>我是匿名插槽组件</h2>
    <slot></slot>
  </div>
</template>

//主页面
<template>
  <div id="app">
    <slot>
      <h4>哈哈哈,我是匿名插槽</h4>
    </slot>
    <!-- <grandSon></grandSon> -->
  </div>
</template>

具名插槽

// comp2
<div>
  <slot></slot>
  <slot name="content"></slot>
</div>

// parent
<Comp2>
  <!-- 默认插槽用default做参数 -->
  <template v-slot:default>具名插槽</template>
  <!-- 具名插槽用插槽名做参数 -->
  <template v-slot:content>内容...</template>
</Comp2>
//父页面
<template>
  <div id="app">
    <example>
      <!-- 默认插槽用default做参数 -->
      <template v-slot:default></template>
      <!-- 具名插槽用插槽名做参数 -->
      <template v-slot:content>
        <h3>我是名为 content的插槽的值 </h3>
      </template>
    </example>
  </div>
</template>
//子页面
<template>
  <div>
    <slot>具名插槽的默认值</slot>
    <slot name="content">
    </slot>
  </div>
</template>

<script>
export default {
  name: "slot",
}
</script>

作用域插槽

// 子组件  
<template>
  <div>
    <slot :foo='foo'>{{foo[0]}}</slot>
  </div>
</template>

<script>
export default {
  name: "slot",
  data() {
    return {
      foo: [' 刘甜', 'hpp']
    }
  },
}
</script>

// parent
<template>
  <div id="app">
   <example>
      <template v-slot="ctx">
        {{ctx.foo[1]}}
      </template>
   </example>
  </div>
</template>

递归数组

//父组件
<template>
  <div>
    <ul>
      <item class="item" :model="treeData"></item>
    </ul>
  </div>
</template>

//循环数据:
 treeData: {
        title: "Web全栈架构师",
        children: [
          {
            title: "Java架构师"
          },
          {
            title: "JS高级",
            children: [
              {
                title: "ES6"
              },
              {
                title: "动效"
              }
            ]
          }
        ]
      }
//子组件
 <template>
  <li>
    <div @click="toggle">
      {{model.title}}
      <span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
    </div>
<ul v-show="open" v-if="isFolder">
  <item class="item" 
        v-for="childmodel in model.children" 
    :model="childmodel" 
    :key="childmodel.title">
  </item>
</ul>
  </li>
</template>

<script>
export default {
  name: "Item",
  props: {
    model: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      open: false
    };
  },
  computed: {
    isFolder() {
      // return this.model.children && this.model.children.length;
      return this.model.children;
    }
  },
  methods: {
    toggle() {
      if (this.isFolder) {
        this.open = !this.open;
      }
    }
  }
};
</script>

猜你喜欢

转载自blog.csdn.net/wjf1997/article/details/105476337