资讯专栏INFORMATION COLUMN

Vue组件基础与通信

I_Am / 3259人阅读

摘要:组件基础与通信一脚手架简介与安装之前安装的是模块,之后安装的是模块。如果是三级组件通信,该如何处理比如父组件与孙子组件通信。和,提供和注入实现祖先组件和后代组件之间通信。

Vue组件基础与通信 一、vue cli脚手架

① vue cli 简介与安装

vue cli 3.0之前安装的是vue-cli模块,vue cli 3.0之后安装的是@vue/cli模块。
如果已经全局安装了旧版本的 vue-cli , 那么需要先卸载vue-cli,再全局安装@vue/cli
虽然安装的是vue cli,但是执行的命令仍然是vue
npm uninstall vue-cli -g // 卸载旧版本脚手架

npm install -g @vue/cli // 安装新版本脚手架

vue --version // 检测是否安装成功

② vue cli 的简单使用

通过create命令创建一个由 vue-cli-service 提供支持的新项目。即会通过vue-cli-service去启动vue项目,从package.json文件中可以看到npm run serve实际执行的是vue-cli-service serve

vue create vue-test // 在当前目录下创建一个vue-test项目,通过问卷的方式选择好需要安装的模块后会自动安装并初始化vue项目

cd vue-test // 进入项目根目录下

npm run serve // 启动vue项目

通过vue serve或者vue build直接启动vue项目,执行vue serve命令的时候可以指定一个.vue文件或者.js文件作为启动入口,如果没有指定启动入口文件,那么就会自动在当前目录下自动寻找main.js、index.js、App.vue 或 app.vue入口文件。

如果入口文件是.js文件,那么其中必须创建一个Vue实例,并且必须添加el属性,且其属性值必须为"#app",并且添加render属性渲染一个Vue组件以便能够显示组件内容。
如果入口文件是.vue文件,那么可以直接渲染,.vue文件中的template里面必须要有一个根元素标签,不限于
,但是不需要添加id为app的根元素,即根元素内容可以任意书写

// main.js

import Vue from "vue";
import App from "./App";

const vm = new Vue({
    el: "#app", // 固定为#app,否则无法显示App组件内容
    render: h => h(App)
});
export default vm; // 可以不对外暴露
二、父子组件通信

如果父组件要向子组件传递数据,那么只需要在子组件中添加一个props属性,其属性值可以是一个数组,数组元素为一个字符串,即父组件给子组件传递数据时所使用的名称,直接在子组件标签中当作元素的一个属性名使用;props属性值也可以是一个对象,对象的属性名为父组件给子组件传递数据时所使用的名称,属性值为一个对象,用于控制父组件传递数据的类型、默认值
// 父组件 Parent.vue

// 子组件 Son.vue


注意,上面子组件中添加了一个按钮用于修改value的属性值,由于Vue规定子组件不能直接去修改父组件的值,所以会报错。即父子组件中的数据是单向的。子组件中如果确实想要修改父组件传递过来的数据,那么可以在子组件中定义一个新的变量,将父组件传递过来的数据保存起来,这个时候子组件去修改这个新的变量对应的值就可以了,但是这样子组件修改的值不会同步到父组件中,因为子组件修改的是自己的数据了
三、父子组件数据同步

① 可以在父组件中使用子组件的时候,在子组件标签上监听一个事件,这个事件名可以任意,比如input事件,这样当子组件内部发射该事件后,子组件就能监听到该事件就可以直接调用父组件中的方法进行处理,如:
//父组件 Parent.vue


 

// 子组件,Son.vue

 
 methods: {
        change() {
            this.$emit("input", "zhang");// 子组件内部发射一个input事件
        }
 }
在父组件使用子组件的时候,给子组件标签上添加了@input="change",子组件渲染的时候,就会在子组件上监听该事件,就相当于 子组件.$on("input", change),即子组件监听到input事件后会触发父组件上change函数的执行,所以该种方式其实就是利用父子组件单向数据流特性,由子组件发起事件,通过修改父组件中的数据来实现父子组件数据的同步,本质就是修改父组件数据

② 父组件向子组件传递数据的时候,使用sync修饰符来修饰子组件上用于接收父组件数据的变量名,同时子组件内部发射一个update:value事件也可以实现父子组件数据的同步更新,如:
// 父组件 Parent.vue

 

// 子组件 Son.vue

methods: {
        change() {
            this.$emit("update:value", "zhang"); // 子组件发射update:value事件
        }
}
sync修饰符其实就是在子组件上绑定值的同时监听了@update:value事件,是一种语法糖,但是子组件上必须发射固定名称的update:value事件才会起作用
需要注意的是,这里所谓的固定名称中value是不固定的,value只是一个子组件用于接收父组件数据时所定义的变量(属性),比如子组件上定义的用于接收父组件的变量是surname,那么子组件就要发射"update:surname"事件了,父组件传递数据的时候就要使用:surname.sync="firstName"了

③ 如果子组件上定义的用于接收父组件数据的属性(变量)是value,并且在子组件中监听的是@input事件,那么我们可以直接简写成v-model,因为v-model实际就是绑定value的值并且监听@input事件,如:
// 父组件 Parent.vue

// 子组件 Son.vue

methods: {
        change() {
            this.$emit("input", "zhang");// 必须是发射input事件
        }
    }
sync和v-model都能实现父子组件数据的同步,但是v-model相对比较局限,属性名必须是value,事件名必须是input,而sync修饰符属性名可以任意。

④ 如果是三级组件通信,该如何处理?比如父组件与孙子组件通信。
同样,我们也可以利用单向数据流的原理,我们只要能够改变父组件上的数据,那么儿子组件和孙子组件上的数据都会进行相应的修改了,而前面父子组件通信的时候是通过子组件发射一个input事件来调用父组件的方法去改变父组件上的数据的,由于孙子组件直接发射一个input事件,父组件上是监听不到,因为父组件上监听的是子组件内部发射的input事件,但是我们可以通过孙子组件的$parent属性获取到子组件,然后通过子组件去发射input事件,那么父组件就能监听到input事件了,从而改变父组件中的数据,实现三级组件通信,如:
// 孙子组件 Grandson.vue

 
Grandson组件: {{value}}
methods: { changeParent() { this.$parent.$emit("input", "Wang");// 通过孙子组件的父组件去发射input事件 } }

⑤ 如果是多级组件通信呢?我也可以通过前面三级组件通信原理,我们只要遍历当前组件的所有祖先组件,然后让所有祖先组件都发射一个input事件,这样一层一层发射input事件,那么最终顶层的父组件肯定能够收到一个input事件从而改变顶层父组件的数据,实现多级组件之间的通信。如:
// main.js 在Vue原型对象上添加一个$dispatch方法,方便后辈组件调用

Vue.prototype.$dispatch = function (eventName, data) { // 切勿使用箭头函数
    let parent = this.$parent; // 获取调用$dispatch方法的父组件
    while(parent) { 遍历祖先组件,一层一层发射相应的事件
        parent.$emit(eventName, data);
        parent = parent.$parent;
    }
}

// 后辈组件

methods: {
        changeParent() {
            this.$dispatch("input", "Wang"); // 派发一个input事件,其祖先组件都会发生input事件
        }
    }

⑥ 有后辈组件向祖先组件派发事件,自然有祖先组件向后辈组件广播事件,所谓广播就是祖先组件通知监听了某个事件的组件都执行一下对应的事件函数,如:
// main.js 在Vue原型对象上添加一个$broadcast方法,方便所有组件调用

Vue.prototype.$broadcast = function(eventName, data) {
    const broadcast = (children) => { // 递归调用broadcast方法
        children.forEach((child) => { // 遍历子组件,每个子组件都发射一个指定的事件
            child.$emit(eventName, data);
            if (child.$children) { // 如果子组件上还有子组件
                broadcast(child.$children) // 递归调用
            }
        });
    }
    broadcast(this.$children);
}

v-bind和$attrs、v-on和$listenners的用法
当我们在组件内部并没有定义props属性来接收父组件传递过来的数据时,这些非prop声明的属性将会原封不动的添加到组件渲染后的html标签上,如:
// Parent.vue父组件


 

Son.vue 子组件

export default {
    props: ["value"] // 子组件上只定义了一个value属性用于接收父组件上的数据
}

子组件渲染完成后,除value属性外,name和age属性都原封不动添加到了html标签上,如:

Son组件: Li
如果不想这些父组件传递过来的非prop属性出现在html标签上,那么可以在子组件上添加一个inheritAttrs属性,并且属性值设置为false
export default {
    inheritAttrs: false, // 不在html标签上继承非prop属性
    props: ["value"] // 子组件上只定义了一个value属性用于接收父组件上的数据
}
需要注意的是虽然设置了inheritAttrs为false,但是子组件上还是具有$attrs属性的,通过$attrs属性还是可以获取到那些来自父组件传递过来的非prop属性的,$attrs为一个对象,对象属性名为非prop属性名,如上子组件上的$attrs值为{name: "Si", age: 18}

如果v-bind不绑定属性,直接赋值一个对象的时候,那么其会将对象的属性名当作组件的属性名,将对象的属性值传递给组件,如:
// Son.vue



所以如果父组件传递给子组件的数据,子组件不想用(子组件并未定义相应的props属性进行接收),但是孙子组件想用,那么可以通过v-bind直接传递给孙子组件,如:
// Son.vue
同样的,还有$listeners,其包含的是
父作用域中不含.native修饰的事件监听器,如上面例子,在父作用域中的Son组件上监听了input事件,那么Son组件内就可以通过$listeners.input()执行input的事件函数。
当然也可以通过v-on="$listeners"传递给孙子组件使用
其主要区别就是: $attrs是组件上属性的集合,$listeners是组件上方法(事件)的集合

⑧ provide和inject,提供和注入实现祖先组件和后代组件之间通信。

可以通过provide()提供一个对象数据到父组件上,然后其后代组件就可以通过inject将祖先组件上的数据注入到后代组件中

// Parent.vue

export default {
    provide() { // 提供一个数据到祖先组件上
        return {
            money: 1000000
        }
    }
}

// Grandson.vue

export default {
    inject: ["money"] // 在后代组件中注入提供到祖先组件上的数据
}
// Grandson组件就可以直接通过this.money获取到数据了

⑨ 获取子组件或者子标签的引用,父组件可以通过$refs属性获取到添加了ref属性的子组件或者子标签对象,然后进行相应的操作,如:


export default {
    mounted() {
        this.$refs.son.say(); // 通过$refs获取到组件,然后调用其say方法
    }
}

⑩ 通过eventBus进行通信,所谓eventBus就是一个公共的Vue实例,所有组件都通过这个公共的Vue实例进行发射和监听事件,如:

Vue.prototype.$bus = new Vue(); // 将这个eventBus对象暴露到原型上方便调用
所有组件都可以获取到这个$bus对象并进行收发数据通信了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106791.html

相关文章

  • vue中8种组件通信方式, 值得收藏!

    摘要:一父组件通过的方式向子组件传递数据,而通过子组件可以向父组件通信。而且只读,不可被修改,所有修改都会失效并警告。 之前写了一篇关于vue面试总结的文章, 有不少网友提出组件之间通信方式还有很多, 这篇文章便是专门总结组件之间通信的 vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢?首先我们需要知道在vue中组件之间存在什么样...

    BicycleWarrior 评论0 收藏0
  • VUE组件化开发的精髓

    摘要:开篇的简单介绍和演示的开发精髓组件组件的三个组件之间的通信方式实例讲解銖宝益帮助中心前端组件开篇的简单介绍和演示发布于年,是一个渐进式的框架,同时也是一个轻量级的框架,它只关心数据,从而让开发者不用过多的关注的改变和操作,的作者为尤雨溪, 开篇:vue.js的简单介绍和演示 vue的开发精髓-组件 vue组件的三个API:prop、event、slot 组件之间的通信方式 实例讲解:銖宝益帮...

    e10101 评论0 收藏0
  • vue组件通信全面总结

    摘要:当一个组件没有声明任何时,这里会包含所有父作用域的绑定和除外,并且可以通过传入内部组件在创建高级别的组件时非常有用。 写在前面 组件间的通信是是实际开发中非常常用的一环,如何使用对项目整体设计、开发、规范都有很实际的的作用,我在项目开发中对此深有体会,总结下vue组件间通信的几种方式,讨论下各自的使用场景 文章对相关场景预览 父->子组件间的数据传递 子->父组件间的数据传递 兄弟...

    余学文 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0

发表评论

0条评论

I_Am

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<