vue 点击事件传递多个参数_连肝3个晚上,我总结了一份Vue实操绝密干货!(共34条)...

这是我学习整理的关于 Vue.js 系列文章的第一篇,另外还有两篇分别是关于优化和原理的。希望读完这3篇文章,你能对 Vue 有个更深入的认识。

7种组件通信方式随你选

组件通信是 Vue 的核心知识,掌握这几个知识点,面试开发一点问题都没有。

props/@on+$emit

用于实现父子组件间通信。通过 props 可以把父组件的消息传递给子组件:

// parent.vue    
<child :title="title"></child>

// child.vue
props: {
    
    title: {
    
        type: String,
        default: '',
    }
}

这样一来 this.title 就直接拿到从父组件中传过来的 title 的值了。注意,你不应该在子组件内部直接改变 prop,这里就不多赘述,可以直接看官网介绍。

而通过 @on+$emit 组合可以实现子组件给父组件传递信息:

// parent.vue
<child @changeTitle="changeTitle"></child>

// child.vue
this.$emit('changeTitle', 'bubuzou.com')

和listeners

Vue_2.4 中新增的 $attrs/$listeners 可以进行跨级的组件通信。$attrs 包含了父级作用域中不作为 prop 的属性绑定(classstyle 除外),好像听起来有些不好理解?没事,看下代码就知道是什么意思了:

// 父组件 index.vue
<list class="list-box" title="标题" desc="描述" :list="list"></list>

// 子组件 list.vue
props: {
    
    list: [],
},
mounted() {
    
    console.log(this.$attrs)  // {title: "标题", desc: "描述"}
}

在上面的父组件 index.vue 中我们给子组件 list.vue 传递了4个参数,但是在子组件内部 props 里只定义了一个 list,那么此时 this.$attrs 的值是什么呢?首先要去除 props 中已经绑定了的,然后再去除 classstyle,最后剩下 titledesc 结果和打印的是一致的。基于上面代码的基础上,我们在给 list.vue 中加一个子组件:

// 子组件 list.vue
<detail v-bind="$attrs"></detial>

// 孙子组件 detail.vue
// 不定义props,直接打印 $attrs
mounted() {
    
    console.log(this.$attrs)  // {title: "标题", desc: "描述"}
}

在子组件中我们定义了一个 v-bind="$attrs" 可以把父级传过来的参数,去除 propsclassstyle 之后剩下的继续往下级传递,这样就实现了跨级的组件通信。

$attrs 是可以进行跨级的参数传递,实现父到子的通信;同样的,通过 $listeners 用类似的操作方式可以进行跨级的事件传递,实现子到父的通信。$listeners 包含了父作用域中不含 .native 修饰的 v-on 事件监听器,通过 v-on="$listeners" 传递到子组件内部。

// 父组件 index.vue
<list @change="change" @update.native="update"></list>

// 子组件 list.vue
<detail v-on="$listeners"></detail>

// 孙子组件 detail.vue
mounted() {
    
    this.$listeners.change()
    this.$listeners.update() // TypeError: this.$listeners.update is not a function
}

provide/inject组合拳

provide/inject 组合以允许一个祖先组件向其所有子孙后代注入一个依赖,可以注入属性和方法,从而实现跨级父子组件通信。在开发高阶组件和组件库的时候尤其好用。

// 父组件 index.vue
data() {
    
    return {
    
        title: 'bubuzou.com',
    }
}
provide() {
    
    return {
    
        detail: {
    
            title: this.title,
            change: (val) => {
    
                console.log( val )
            }
        }
    }
}

// 孙子组件 detail.vue
inject: ['detail'],
mounted() {
    
    console.log(this.detail.title)  // bubuzou.com
    this.detail.title = 'hello world'  // 虽然值被改变了,但是父组件中 title 并不会重新渲染
    this.detail.change('改变后的值')  // 执行这句后将打印:改变后的值 
}
provideinject 的绑定对于原始类型来说并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。这也就是为什么在孙子组件中改变了 title,但是父组件不会重新渲染的原因。

EventBus

以上三种方式都是只能从父到子方向或者子到父方向进行组件的通信,而我就比较牛逼了 ,我还能进行兄弟组件之间的通信,甚至任意2个组件间通信。利用 Vue 实例实现一个 EventBus 进行信息的发布和订阅,可以实现在任意2个组件之间通信。有两种写法都可以初始化一个 eventBus 对象:

  1. 通过导出一个 Vue 实例,然后再需要的地方引入:
    // eventBus.js
    import Vue from 'vue'
    export const EventBus = new Vue()
    使用 EventBus 订阅和发布消息:
    import {EventBus} from '../utils/eventBus.js'
    // 订阅处
    EventBus.$on('update', val => {})
    // 发布处
    EventBus.$emit('update', '更新信息')
  2. main.js 中初始化一个全局的事件总线:
    // main.js
    Vue.prototype.$eventBus = new Vue()
    使用:
    // 需要订阅的地方
    this.$eventBus.$on('update', val => {})
    // 需要发布信息的地方
    this.$eventBus.$emit('update', '更新信息')

如果想要移除事件监听,可以这样来:

this.$eventBus.$off('update', {})

上面介绍了两种写法,推荐使用第二种全局定义的方式,可以避免在多处导入 EventBus 对象。这种组件通信方式只要订阅和发布的顺序得当,且事件名称保持唯一性,理论上可以在任何 2 个组件之间进行通信,相当的强大。但是方法虽好,可不要滥用,建议只用于简单、少量业务的项目中,如果在一个大型繁杂的项目中无休止的使用该方法,将会导致项目难以维护。

Vuex进行全局的数据管理

Vuex 是一个专门服务于 Vue.js 应用的状态管理工具。适用于中大型应用。Vuex 中有一些专有概念需要先了解下:

  • State:用于数据的存储,是 store 中的唯一数据源;
  • Getter:类似于计算属性,就是对 State 中的数据进行二次的处理,比如筛选和对多个数据进行求值等;
  • Mutation:类似事件,是改变 Store 中数据的唯一途径,只能进行同步操作;
  • Action:类似 Mutation,通过提交 Mutation 来改变数据,而不直接操作 State,可以进行异步操作;
  • Module:当业务复杂的时候,可以把 store 分成多个模块,便于维护;

对于这几个概念有各种对应的 map 辅助函数用来简化操作,比如 mapState,如下三种写法其实是一个意思,都是为了从 state 中获取数据,并且通过计算属性返回给组件使用。

computed: {
    
    count() {
    
        return this.$store.state.count
    },
    ...mapState({
    
        count: state => state.count
    }),
    ...mapState(['count']),
},

又比如 mapMutations, 以下两种函数的定义方式要实现的功能是一样的,都是要提交一个 mutation 去改变 state 中的数据:

methods: {
    
    increment() {
    
        this.$store.commit('increment')
    },
    ...mapMutations(['increment']),
}

接下来就用一个极简的例子来展示 Vuex 中任意2个组件间的状态管理。1、 新建 store.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
    
export default new Vuex.Store({
    
    state: {
    
        count: 0,
    },
    mutations: {
    
        increment(state) {
    
            state.count++
        },
        decrement(state) {
    
            state.count--
        }
    },
})

2、 创建一个带 storeVue 实例

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './utils/store'
    
new Vue({
    
    router,
    store,
    render: h => h(App)
}).$mount('#app')

3、 任意组件 A 实现点击递增

<template>
    <p @click="increment">click to increment:{
    {
    count}}</p>
</template>
<script>
import {
    mapState, mapMutations} from 'vuex'
export default {
    
    computed: {
    
        ...mapState(['count'])
    },
    methods: {
    
        ...mapMutations(['increment'])
    },
}
</script>

4、 任意组件 B 实现点击递减

<template>
    <p @click="decrement">click to decrement:{
    {
    count}}</p>
</template>
<script>
import {
    mapState, mapMutations} from 'vuex'
export defaul
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值