vue2.x组件通讯方法
2020/7/30 vue
# props
// 数组:不建议使用
props:[]
// 对象
props:{
inpVal:{
type: Number, //传入值限定类型
// type 值可为String,Number,Boolean,Array,Object,Date,Function,Symbol
// type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认
required: true, //是否必传
default:200, //默认值,对象或数组默认值必须从一个工厂函数获取如 default:()=>[]
validator:(value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# $emit
// 父组件
<home @title="setTitle">
// 子组件
this.$emit('title',{title:'这是title'})
1
2
3
4
5
2
3
4
5
v-model
//把input输入框的value属性值和vue实例的message属性进行绑定,同时监听输入事件。
<input v-bind:value="message" v-on:input="message = $event.target.value" />
// v-model 是 @input 与 value 的语法糖
1
2
3
4
2
3
4
v-bind
: vue2.x v-bind (opens new window)
<!-- 绑定一个 attribute -->
<img v-bind:src="imageSrc">
<!-- 动态 attribute 名 (2.6.0+) -->
<button v-bind:[key]="value"></button>
<!-- 缩写 -->
<img :src="imageSrc">
<!-- 动态 attribute 名缩写 (2.6.0+) -->
<button :[key]="value"></button>
<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName">
<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!-- 绑定一个全是 attribute 的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- 通过 prop 修饰符绑定 DOM attribute -->
<div v-bind:text-content.prop="text"></div>
<!-- prop 绑定。“prop”必须在 my-component 中声明。-->
<my-component :prop="someThing"></my-component>
<!-- 通过 $props 将父组件的 props 一起传给子组件 -->
<child-component v-bind="$props"></child-component>
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!-- 方法处理器 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>
<!-- 内联语句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 动态事件缩写 (2.6.0+) -->
<button @[event]="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!-- 串联修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 键修饰符,键别名 -->
<input @keyup.enter="onEnter">
<!-- 键修饰符,键代码 -->
<input @keyup.13="onEnter">
<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 对象语法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
<!-- 监听自定义事件 -->
<my-component @my-event="handleThis"></my-component>
<!-- 内联语句 -->
<my-component @my-event="handleThis(123, $event)"></my-component>
<!-- 组件中的原生事件 -->
<my-component @click.native="onClick"></my-component>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
v-cloak
<!-- css -->
div[v-cloak] {
display: none;
}
<!-- body -->
<div id="app" v-cloak>
{{ message }}
</div>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# vuex
state: // 定义存贮数据的仓库 ,可通过this.$store.state 或mapState访问
getter: // 获取 store 值,可认为是 store 的计算属性,可通过this.$store.getter 或 mapGetters访问
mutation: // 同步改变 store 值,为什么会设计成同步,因为mutation是直接改变 store 值,
// vue 对操作进行了记录,如果是异步无法追踪改变.可通过mapMutations调用
action: // 异步调用函数执行mutation,进而改变 store 值,可通过 this.$dispatch或mapActions访问
modules: // 模块,如果状态过多,可以拆分成模块,最后在入口通过...解构引入
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# attrs和listeners
- attrs获取子传父中未在 props 定义的值
// 父组件
<home title="这是标题" width="80" height="80" imgUrl="imgUrl"/>
// 子组件
mounted() {
console.log(this.$attrs) //{title: "这是标题", width: "80", height: "80", imgUrl: "imgUrl"}
},
1
2
3
4
5
6
7
2
3
4
5
6
7
- 如果子组件定义了 props,打印的值就是剔除定义的属性
props: {
width: {
type: String,
default: ''
}
},
mounted() {
console.log(this.$attrs) //{title: "这是标题", height: "80", imgUrl: "imgUrl"}
},
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- listeners 传入内部组件
// 父组件
<home @change="change"/>
// 子组件
mounted() {
console.log(this.$listeners) //即可拿到 change 事件
}
-----------------------------
// 父组件
<home v-on="$listeners"/>
// 例如 自定义 element-ui的table组件
<template>
<el-table
:data="data"
v-bind="$attrs"
v-on="$listeners"
>
// ...
</el-table>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- inheritAttrs
// 父组件
<home title="这是标题" width="80" height="80" imgUrl="imgUrl"/>
// 子组件
mounted() {
console.log(this.$attrs)
//{title: "这是标题", width: "80", height: "80", imgUrl: "imgUrl"}
},
// inheritAttrs默认值为true,是将父组件中除了props外的属性添加到子组件的根节点上
// 说明,即使设置为true,子组件仍然可以通过$attr获取到props意外的属性
// 将inheritAttrs:false 后,属性就不会显示在根节点上了
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# provide和inject
//父组件:
provide: { //provide 是一个对象,提供一个属性或方法
foo: '这是 foo',
fooMethod:()=>{
console.log('父组件 fooMethod 被调用')
}
},
// 子或者孙子组件
inject: ['foo','fooMethod'], //数组或者对象,注入到子组件
mounted() {
this.fooMethod()
console.log(this.foo)
}
//在父组件下面所有的子组件都可以利用inject
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- provide 和 inject 绑定并不是可响应的
//父组件:
provide: {
foo: '这是 foo'
},
mounted(){
this.foo='这是新的 foo'
}
// 子或者孙子组件
inject: ['foo'],
mounted() {
console.log(this.foo) //子组件打印的还是'这是 foo'
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- provide和inject响应方法
// 父组件
provide() {
return {
staticValue: this.staticValue, // 直接返回值,不可响应
staticObject: this.staticObject, // 返回一个对象,可响应
getReactiveValue: () => this.staticValue // 返回一个对象的函数,可响应
}
},
// 子组件
inject: ["staticValue", "getReactiveValue", "staticObject"],
computed: {
reactiveValue() {
return this.getReactiveValue(); // 返回注入的对象函数,通过计算属性来监听值的变化
},
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# parent和children
//父组件
mounted(){
console.log(this.$children)
//可以拿到 一级子组件的属性和方法
//所以就可以直接改变 data,或者调用 methods 方法
}
//子组件
mounted(){
console.log(this.$parent)
//可以拿到 parent 的属性和方法
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# $refs
// 父组件
<home ref="home"/>
mounted(){
console.log(this.$refs.home)
//即可拿到子组件的实例,就可以直接操作 data 和 methods
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# .sync
修饰符
// 父组件
<home :title.sync="title" />
//编译时会被扩展为
<home :title="title" @update:title="val => title = val"/>
// 子组件
// 所以子组件可以通过$emit 触发 update 方法改变
mounted(){
this.$emit("update:title", '这是新的title')
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# v-slot
- 默认
// 父组件
<todo-list>
<template v-slot:default>
任意内容
<p>我是匿名插槽 </p>
</template>
</todo-list>
// 子组件
<slot>我是默认值</slot>
//v-slot:default写上感觉和具名写法比较统一,容易理解,也可以不用写
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 具名插槽
// 父组件
<todo-list>
<template v-slot:todo>
任意内容
<p>我是具名插槽 </p>
</template>
</todo-list>
//子组件
<slot name="todo">我是默认值</slot>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 作用域插槽
// 父组件
<todo-list>
<template v-slot:todo="slotProps" >
{{slotProps.user.firstName}}
</template>
</todo-list>
//slotProps 可以随意命名
//slotProps 接取的是子组件标签slot上属性数据的集合所有v-bind:user="user"
// 子组件
<slot name="todo" :user="user" :test="test">
{{ user.lastName }}
</slot>
data() {
return {
user:{
lastName:"Zhang",
firstName:"yue"
},
test:[1,2,3,4]
}
},
// {{ user.lastName }}是默认数据 v-slot:todo 当父页面没有(="slotProps")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# EventBus
// 在 main.js
Vue.prototype.$eventBus=new Vue()
// 传值组件
this.$eventBus.$emit('eventTarget','这是eventTarget传过来的值')
// 接收组件
this.$eventBus.$on("eventTarget",v=>{
console.log('eventTarget',v);//这是eventTarget传过来的值
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# broadcast和dispatch
// 派发事件
vue.prototype.$dispatch = function(eventName, value) {
let parent = this.$parent;
while (parent) {
parent.$emit(eventName, value);
parent = parent.$parent;
}
};
// 广播事件
Vue.prototype.$broadcast = function(eventName, value) {
let broadcast = children => {
children.forEach(child => {
child.$emit(eventName, value);
if (child.$children) {
broadcast(child.$children);
}
});
};
broadcast(this.$children);
};
/*
inheritAttrs: false // 绑定的属性不在dom上显示 :<div name="xxx"></div> 不显示
v-bind="$attrs" // 将 $attrs 上所有属性绑定到dom上传递给子组件
v-on="$listeners" // 表示将方法绑定到dom上传递给子组件
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 路由传参
- 方案一
// 路由定义
{
path: '/describe/:id',
name: 'Describe',
component: Describe
}
// 页面传参
this.$router.push({
path: `/describe/${id}`,
})
// 页面获取
this.$route.params.id
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 方案二
// 路由定义
{
path: '/describe',
name: 'Describe',
component: Describe
}
// 页面传参
this.$router.push({
name: 'Describe',
params: {
id: id
}
})
// 页面获取
this.$route.params.id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 方案三
// 路由定义
{
path: '/describe',
name: 'Describe',
component: Describe
}
// 页面传参
this.$router.push({
path: '/describe',
query: {
id: id
`}
)
// 页面获取
this.$route.query.id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Vue.observable
// store/store.js
import Vue from 'vue'
export const store = Vue.observable({ count: 0 })
export const mutations = {
setCount (count) {
store.count = count
}
}
//使用
<template>
<div>
<label for="bookNum">数 量</label>
<button @click="setCount(count+1)">+</button>
<span>{{count}}</span>
<button @click="setCount(count-1)">-</button>
</div>
</template>
<script>
import { store, mutations } from '../store/store' // Vue2.6新增API Observable
export default {
name: 'Add',
computed: {
count () {
return store.count
}
},
methods: {
setCount: mutations.setCount
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# $root
// 父组件
mounted(){
console.log(this.$root) //获取根实例,最后所有组件都是挂载到根实例上
console.log(this.$root.$children[0]) //获取根实例的一级子组件
console.log(this.$root.$children[0].$children[0]) //获取根实例的二级子组件
}
1
2
3
4
5
6
2
3
4
5
6
# 其他
- window.localStorage的方式
- 服务端接口