Vue 2 传参方式(全)

1,144 阅读1分钟

自己总结 ,欢迎讨论指正,如果能帮到你,请点个免费的赞👍

子传父

单向数据流

  1. 单项数据流是发生在父子组件传值时,父组件通过prop向子组件传递数据。—— 父级prop的更新会向下流动到子组件中,但是反过来则不行。
  2. 这样会防止从子组件意外改变父组件的状态。每次父级组件发生更新时,子组件中所有的prop都将会刷新为最新的值。
  3. 子组件想修改时,只能通过$emit触发一个自定义事件,父组件接收到后,由父组件修改。

1. $emit

在子组件上绑定某个事件以及事件触发的函数,在父组件中绑定触发事件,接收子组件传递的数据。

  • 子组件
<template>
    <div class="app">
       <input @click="sendMsg" type="button" value="给父组件传递值">
    </div>
</template>
<script>
export default {
 
    data () {
        return {
            msg: "我是子组件的msg",   //将msg传递给父组件
        }
    },
     methods:{
         sendMsg(){
             //func: 是父组件指定的传数据绑定的函数,this.msg:子组件给父组件传递的数据
             this.$emit('func',this.msg)
         }
     }
}
</script>
  • 父组件
<template>
    <div class="app">
        <child @func="getMsgFormSon"></child>
    </div>
</template>
<script>
import child from './child.vue'
export default {
    data () {
        return {
            msgFormSon: "this is msg"
        }
    },
    components:{
        child,
    },
    methods:{
        getMsgFormSon(data){
            this.msgFormSon = data
        }
    }
}
</script>

2.$refs

通过$ref的能力,给子组件定义一个ID,父组件通过这个ID可以直接访问子组件里面的方法和属性

  • 子组件
<template>
    <div>
       <Tree :data="treeData" show-checkbox ref="treeData"></Tree>
    </div>
</template>
<!-- 定义方法 -->
getData(){
    return this.$refs.treeData.getCheckedNodes()
},
  • 父组件
<AuthTree ref="authTree"></AuthTree>
<!-- 调用方式 -->
console.log( this.$refs.authTree.getData());

父传子

1. prop

父组件使用prop把数据传给子组件

  • 子组件
export default {
  name: 'ExGroupSearchTree',
  components,
  props: {
    selectedKeys: {
      type: Array,
      default: function() {
        return []
      },
    },
    isSearch: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {},
  },
  methods: {},
}
  • 父组件
<div>
  <ex-group-search-tree
    :key="key"
    :selected-keys="defaultSelectedKeys"
    :is-search="true"
    @treeSelect="treeSelect"
  ></ex-group-search-tree>
</div>

2.provide、inject(依赖注入)

向下传递(可注入其子孙的属性),适用于嵌套多层组件时。

注意:当provide提供的是一个对象时,变化后会更新到子组件里,如果是个值不行

  • 父组件

父组件发送需要传入的参数

  data: function() {
    return {}
  },
  provide() {
    return {
      isAnony: this.isAnony,
    }
  },
  methods: {},
  • 子组件

子组件接收

  data() {
    return {}
  },
  inject: {
    isAnony: { default: false },
  },
  created() {}

3.$props、$attrs、v-on="$listeners"

多用于三层组件嵌套,祖孙组件通信时,父组件通过propsprops、attrs来接收外层组件的参数,通过v-on="$listeners"来监听外层组件的方法,都需要一层一层向下传递。

$props:当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象属性的访问。将属性向下传递

$attrs:包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。将属性向下传递(例如:没有在props中定义的key,但是在标签中定义)

  • 中间组件
<template>
  <div>
    <oa-ex-unit-picker v-if="isXcex" v-bind="{ ...$props }" v-on="$listeners" />
    <oa-group-unit-picker v-else v-bind="{ ...$props }" v-on="$listeners" />
  </div>
</template>

<script>
import components from './_import-components/oa-unit-picker-import'

export default {
  name: 'OaUnitPicker',
  components,
  props: {
    value: {
      type: [Array, String],
      default: function() {
        return []
      },
    },
    rootNode: {
      type: [Array],
      default: function() {
        return null
      },
    },
    hierarchical: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      isXcex: true, // 是否启用 新公文交换开关
    }
  },
  methods: {},
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
</style>

兄弟组件

1. eventBus

image

Publisher(发布者)通过post()方法,把Event事件发布出去,Subscriber(订阅者)在onEvent()方法中接收事件

  • 初始化——全局定义

全局定义,可以将eventBus绑定到vue实例的原型上,也可以直接绑定到window对象上.

//main.js
//方式一
Vue.prototype.$EventBus = new Vue();
//方式二
window.eventBus = new Vue();
  • 触发事件
//使用方式一定义时
this.$EventBus.$emit('eventName', param1,param2,...)
//使用方式二定义时
EventBus.$emit('eventName', param1,param2,...)
  • 监听事件
//使用方式一定义时
this.$EventBus.$on('eventName', (param1,param2,...)=>{
    //需要执行的代码
})
//使用方式二定义时
EventBus.$on('eventName', (param1,param2,...)=>{
    //需要执行的代码
})
  • 移除监听事件

为了避免在监听时,事件被反复触发,通常需要在页面销毁时移除事件监听。或者在开发过程中,由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听。

//使用方式一定义时
this.$EventBus.$off('eventName');
//使用方式二定义时
EventBus.$off('eventName');

2.VueX

vuex 是一个专门为vue.js应用程序开发的状态管理模式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MrJqsMCM-1665458801322)(segmentfault.com/img/bVbfPQV…)]

可以理解为在data中的属性,需要共享给其他组件使用的部分,,使用vuex进行统一集中式的管理。

  • vuex中,有默认的五种基本的对象:
    • state:存储状态(变量)
    • getters:对数据获取之前的再次编译,可以理解为state的计算属性。我们在组件中使用 $sotre.getters.fun()
    • mutations:修改状态,并且是同步的。在组件中使用$store.commit('',params)。这个和我们组件中的自定义事件类似。
    • actions:异步操作。在组件中使用是$store.dispath('')
    • modules:store的子模块,为了开发大型项目,方便状态管理而使用的。这里我们就不解释了,用起来和上面的一样。
  • 在store.js文件中,引入vuex并且使用vuex
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
    count: 0
}

export default new Vuex.Store({
    state
})
  • 在其他组件中就可以使用定义的属性了
<template>
  <div class="hello">
    <h3>{{$store.state.count}}</h3>
  </div>
</template>
  • 用mutations和actions操作VueX中的属性
  • store.js
/**
 * mutations 里面放置的是我们操作state对象属性的方法
 */
const mutations = {
    mutationsAddCount(state, n = 0) {
        return (state.count += n)
    },
    mutationsReduceCount(state, n = 0) {
        return (state.count -= n)
    }
}
export default new Vuex.Store({
    state,
    mutations
})
  • helloWorld.vue
<template>
  <div class="hello">
    <h3>{{$store.state.count}}</h3>
    <div>
      <button @click="handleAddClick(10)">增加</button>
      <button @click="handleReduceClick(10)">减少</button>
    </div>
  </div>
</template>
methods: {
    handleAddClick(n){
      this.$store.commit('mutationsAddCount',n);
    },
    handleReduceClick(n){
      this.$store.commit('mutationsReduceCount',n);
    }
}
  • actions(异步操作),dispatch
  • store.js
const actions = {
    actionsAddCount(context, n = 0) {
        console.log(context)
        return context.commit('mutationsAddCount', n)
    },
    actionsReduceCount({ commit }, n = 0) {
        return commit('mutationsReduceCount', n)
    }
}
export default new Vuex.Store({
    state,
    mutations,
    actions
})
  • helloWorld.vue
<div>
    <button @click="handleActionsAdd(10)">异步增加</button>
    <button @click="handleActionsReduce(10)">异步减少</button>
</div>
handleActionsAdd(n){
    this.$store.dispatch('actionsAddCount',n)
},
handleActionsReduce(n){
    this.$store.dispatch('actionsReduceCount',n)
}
  • getters

使用getters来获取我们的state,因为它算是state的一个计算属性

  • store.js
const getters = {
    getterCount(state, n = 0) {
        return (state.count += n)
    }
}
export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters
})
  • helloWorld.vue
<h4>{{count}}</h4>
const getters = {
    getterCount(state) {
        return (state.count += 10)
    }
}

插槽(传值)

让父组件可以向子组件指定位置插入html结构,也是一种组件通信的方式

  • 默认插槽

父组件向子组件发送title

  • fath文件
<template>
    <son :title="电影">
        <ul>
            <li v-for="(item,index) in films" :key="index">{{ item }}</li>
        </ul>
    </son>
</template>

<script>
    export default{
        name:'fath',
        components:{ son },
        data:{
            return {
                films:['猫和老鼠','哆唻A梦','樱桃小丸子']
            }
        }
    }
</script>
  • son文件
<template>
    <div>
        <h3>{{ title }}</h3>
        <!-- 定义一个插槽(设置一个位置,等着组件的使用者进行填充) -->
        <slot>这是一个插槽,当使用插槽时,此文字不展示被填充内容覆盖</slot>
    </div>
</template>

<script>
    export default{
        name:'son',
        props:['listData','title']
    }
</script>
  • 具名插槽

当有多个slot时,为了对应起来,可以给slot起名字,传递的时候对应起来。

  • fath

    <div>
        <son>
            <div v-slot:content>
                <span>{{ 给内容区放点东西 }}</span>
            </div>
            <!-- vue 2.6版本后语法,在template中可以直接写v-slot:slot1 -->
            <template slot="footer">
                <div> 
                    <span>{{ 给底部放点东西 }}</span>
                </div>
            </template>
        </son>
    </div>
    
  • son

    <template>
        <h2>{{ 这里是头部 }}</h2>
        <slot name='content'>这里是内容插槽,当使用插槽时,此文字不展示被填充内容覆盖</div>
        <slot name='footer'>这里是底部插槽,当使用者没有传递具体结构时,此文字会显示</div>
    </template>
    
  • 作用域插槽

数据在子组件中,父组件可以取到并对数据的结构进行调整

子组件的数据可以被外层父组件使用

  • fath
<son>
    <template scope="scopeData">
        <span v-for="item in scopeData.films">{{ item }}</span>
    </template>
    <template slot-scope="scopeData">
        <h3 v-for="item in scopeData.films">{{ item }}</h3>
    </template>
    <template v-slot:default="scopeData">
        <ul>
            <li v-for="item in scopeData.films">{{ item }}</li>
        </ul>
    </template>
</son>
  • son
<template>
    <div>
        <slot :film="film">
    </div>
</template>

<script>
    export default{
        name:'son',
        data:{
            return {
                films:['猫和老鼠','哆唻A梦','樱桃小丸子']
            }
        }
    }
</script>