1.props
2.$emit/$on
3.$parent/$children
4.ref
5.$attrs / $listeners
6.$root
7.eventBus
8.vuex
props
父子组件通信
1 props 父传子
1.父组件以属性的方式传值给子组件
2.子组件通过props方式接收数据
父组件核心代码
在父组件中引入子组件并绑定parentData自定义属性
<Child:parentData="parentData"></Child >
<script>
import Child from '@/components/child'
export default{
name:'Parent',
components:{Child},
data(){
return{
parentData:'我是父组件向子组件传递的值-props方式'
}
}
}
</script>
子组件核心代码
1.在子组件中使用 props 接收父组件传递的数据,
2.props 里的名字跟父组件定义的属性名一致
<template>
<div>我是父组件的数据:{{parentData}}</div>
<div>我是父组件传递修改后的数据:{{mydata}}</div>
</template>
<script>
export default{
name:'Child',
props:{
parentData:{
type:String,
default:''
}
}
data(){
mydata:'俺的小破站 '+ this.parentData
},
watch:{
parentData(newVal){
this.mydata='俺的小破站 '+ newVal
}
},
}
</script>
Vue的单向数据流机制,子组件不能够直接去修改父组件传递的值修改的,否则能改的话那父组件的值就被污染了。
但是子组件内想要修改父组件传过来的值却不“污染”父组件的话,
可以在子组件内定义一个变量mydata去接收parentData数据,并使用 watch 监听parentData数据的变更
$emit/$on 子传父
1.子组件绑定自定义事件
2.使用 $emit() 触发更改数据
子组件核心代码
<el-button @click="handleEmit">告诉父组件我要更改数据啦</el-button>
<script>
export default{
name:'Child',
methods:{
handleEmit(){
this.$emit('triggerEmit','我是来自子组件的数据')
}
}
}
</script>
父组件核心代码
1.父组件定义并绑定子组件传递的triggerEmit事件
2.triggerEmit事件名需跟子组件 $emit() 的事件名
<Child @triggerEmit="changeData"></Child>
<script>
import Child from '@/components/child'
export default{
name:'Parent',
components:{Child},
methods:{
changeData(name){
console.log(name) // => 我是来自子组件的数据
}
}
}
</script>
$parent/$children
1.子组件通过 $parent 获得父组件实例
2.父组件通过 $children 获得子组件实例数组
子组件
<template>
<div>我是子组件</div>
</template>
<script>
export default{
name:"Child",
data(){
return{
childTitle: '我是子组件的数据'
}
},
methods:{
childHandle(){
console.log('我是子组件的方法')
}
},
created(){
console.log(this.$parent)
console.log(this.$parent.parentTitle) // => 我是父组件的数据
this.$parent.parentHandle() // => 我是父组件的方法
}
}
</script>
this.$parent可以获取到父组件的方法、data的数据等,并可以直接使用和执行。
父组件
<template>
<div>
<Child>我是父组件</Child>
</div>
</template>
<script>
import Child from './child.vue'
export default{
name: 'parent',
components:{
Child
},
data(){
return{
parentTitle: '我是父组件的数据'
}
},
methods:{
parentHandle(){
console.log('我是父组件的方法')
}
},
mounted(){
console.log(this.$children)
console.log(this.$children[0].childTitle) // => 我是子组件的数据
this.$children[0].childHandle() // => 我是子组件的方法
}
}
</script>
注意钩子的使用
父组件是在 mounted()生命周期中获取子组件实例的,并且获取的实例是一个数组形式
层级发生变化的时候咋办呢 ???
1.源码其实有更高层次的封装,在引用parent到时候抽象一个更高级的方法类似 dispatch,
2.直接指定比较重要的父组件的类型或者名称,在循环查找的时候避免程序的脆弱性
ref
父组件使用 $refs 获得组件实例
<template>
<div>
<Child ref="child"></Child >
</div>
</template>
<script>
import Child from './child.vue'
export default{
name: 'parent',
components:{
Child
},
mounted(){
console.log(this.$refs.child ) /*组件实例*/
}
}
</script>
1.注意 钩子 mounted
父组件就可以直接使用this.$refs.xx获取子组件的实例
$attrs/$listeners
- 兄弟组件
核心就是找共同点, 搭建桥梁,中间人,话事人的感觉
$parent
既然是兄弟往上找 总能找到共同的祖先
不常用,可以参考文章上面 的 写法
$root
其实 根也是共享的
eventBus
也是都可以访问的
创建一个Vue实例
作为调度中心 eventBus
import Vue from "vue"
export default new Vue()
需要进行通信的组件中 引入
<template>
<div>
<div>我是通信组件A</div>
<el-button @click="changeName">修改</el-button>
</div>
</template
<script>
import { EventBus } from "../bus.js"
export default{
data(){
return{}
},
methods:{
changeName(){
EventBus.$emit("editName", '俺的小破站')
}
}
}
</script>
监听事件
<template>
<div>我是通信组件B</div>
</template
<script>
import { EventBus } from "../bus.js"
export default{
data(){
return{}
},
mounted:{
EventBus.$on('editName',(name)=>{
console.log(name) // 俺的小破站!
})
}
}
</script>
vuex
1.Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
2.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测 的方式发生变化
3.Vuex 也集成到 Vue 的官方调试工具
npm 安装
npm install vue --S
需要 简单的配置
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
组件 A 模板 重点
< button @click="add()" >传给兄弟组件 -- {{num}}</button>组件 A 传值
重要 的是创建了一个 中间 Vue 实例对象 用于周转
这个就是 事件中心 event bus
创建一个空的vue实例对象,目的是实现兄弟组件之间的交互
var bus = new Vue({});
add(){
this.num++;
// /当组件需要给其他组件传值时,可以调用总线bus的$emit发射一个事件,需要接收这个传值的组件监听这个事件即可。
bus.$emit("changeData",this.num);
},
组件B
核心代码 是监听 组件A 的事件
created(){
// 此时this指代自定义的f_view对象,记录该对象
var _this = this;
console.log(this);
// 接收传值的组件需要监听总线bus上的传值事件
// 通过bus.$on添加总线事件监听,第一个参数是监听的事件类型,第二个参数是事件绑定的函数,事件函数的参数就是发射事件时所传递的参数。
bus.$on("changeData",function(a){
// 此时的this指代vue实例tempVe对象
// a接收事件发射传递过来的num值 --- h_view中的数据源
console.log(a);
_this.count = a;
});
}
并不是所有的项目都适合 用vuex,适合自己的才是最好的
还有哪些可以变向管理状态或者说 页面共享数据
dataset
cookie
storage
极端情况 window 挂载属性
provide/inject
父组件使用 provide 注入数据
子组件使用 inject 使用数据
父组件
export default{
provide: {
return{
provideName: '俺的小破站'
}
}
}
分析
provideName这个变量可以提供给它其下的所有子组件,包括曾孙、孙子组件等,只需要使用 inject 就能获取数据
子组件
export default{
inject: ['provideName'],
created () {
console.log(this.provideName) // 俺的小破站
}
}
优缺点
1.父组件不需要知道哪个组件使用它提供出去的数据
2.子组件不需要知道这个数据从哪里来
3.更加的原生,不会对第三方库产生依赖
缺点:单向的;只能祖辈向子辈传值
vue3 通信方式
props和emit
setup函数可以接受两个参数, prop 和 context ,其中context可以解构出emit slots attrs
利用 emit实例来传参
子组件 代码
<template>
<el-button @click="handle">子组件 ---点击</el-button>
<div>我是父组件传过来的数据:{{name}}</div>
</template>
<script>
export default {
name:"Child",
props: {
name: {
type: String,
default: ''
}
},
setup(props,{ emit }) {
console.log(props.name) // yzs
function handle() {
emit('handleClick', 'Vue3 学起来')
}
return {
handle
}
}
}
</script>
简要分析
Vue3中没有this的概念了,所以就不会有this.$emit存在,
所以可以从setup传入的context解构出emit实例,从而派发事件给父组件
父组件
<template>
<Test name="yzs" @handleClick="myClick">父组件---点呀</Test>
</template>
<script>
import Test from './index.vue'
export default {
name:"parent",
components: { Test },
setup() {
function myClick(name) {
console.log(name)// Vue3 学起来
}
return {
myClick
}
}
}
</script>
ref
Vue3我们可以从Vue中导出 ref 方法,得到子组件的实例
分析
1.通过,在子组件声明ref属性,
2.属性值必须和const btnRef = ref(null)这里声明的变量名一致,否则会报错
3.拿到子组件实例后就可以直接调用组件的sendParent方法了
父组件代码
<template>
<Test ref="btnRef">
<el-button @click="click">点我呀</el-button>
</Test>
</template>
<script>
import { ref } from "vue"
import Test from './index.vue'
export default {
components: {Test},
setup() {
const btnRef = ref(null)
function click() {
btnRef.value?.sendParent() // 我是给父组件调用的方法
}
return {
btnRef,
click
}
}
}
</script>
这里使用的btnRef.value?.是可选链操作符语法,
代表?前面的值为true才继续执行后面的语句
使用
<template>
<slot></slot>
</template>
<script>
export default {
setup() {
function sendParent() {
console.log("我是给父组件调用的方法")
}
return {
sendParent
}
}
}
</script>
provide/inject
和vue2差不离儿
父组件
<template>
<Test></Test>
</template>
<script>
import { provide } from "vue"
import Test from './index.vue'
export default {
components: {Test},
setup() {
//我已经把数据注入到fromParent里面去了
provide('fromParent', '俺的小破站')
return {}
}
}
</script>
子组件
<template>
<slot></slot>
<div>我是父组件注入的数据:{{parentData }}</div>
</template>
<script>
import { inject } from "vue"
export default {
setup() {
//我来去父组件注入的数据
let parentData = inject('fromParent')
return {
parentData
}
}
}
</script>
子孙组件使用inject获取到父组件注入的数
区别
其实主要就是 Vue3采用了 这个模块化
所以inject 和 provide 需要单独导入
nextTick 是什么
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
官方案例
// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick(function () {
// DOM 更新了
})
// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)
Vue.nextTick()
.then(function () {
// DOM 更新了
})
为什么 需要nextTick
由于vue的异步更新策略导致我们对数据的修改不会立刻体现在dom变化上,此时如果想要立即获取更新后的dom状态,就需要使用这个方法
vue在更新DOM时是异步执行的.只要侦听到数据变化,vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更.如果同一个watcher被多次触发,只会会被推入到队列中1次.
这种在缓冲时取出重复数据对于避免不必要的计算和DOM操作是非常重要的.
nextTick方法会在队列中加入一个回调函数,确保该函数在前面的DOM 操作完成后才调用
所以当我们想在数据修改后立即看到都DOM执行结果就需要用到nextTick方法
本文共 1897 个字数,平均阅读时长 ≈ 5分钟
评论 (0)