7天深入Vue - vue组件之间的通讯与插槽(一)
2021-02-11 本文已影响0人
申_9a33
常用组件之间的通讯
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>