<Child :count="count" :add="add" />
export default {
name: "Child",
// 不声明props接受属性,属性就在$attrs
props: ["count"],
props: {
count: Number,
},
// props数据是只读不能修改
props: {
count: {
type: Number,
required: true,
validator(value) {
return value >= 0 && value <= 10;
},
// default: 0
},
add: {
type: Function,
required: true,
},
},
inheritAttrs: false, // 是否显示在元素标签上
};
<button @click="handleClick">按钮</button>
<MyButton @click="handleClick($event)" @xxx="xxx($event)" />
事件:
原生DOM元素绑定事件
事件名是原生DOM事件事件名,绑定就是原生DOM事件
事件名不是原生DOM事件事件名,绑定就是自定义事件
组件绑定事件
所有事件都是自定义事件
一般只会给组件绑定自定义事件,给普通元素绑定没有意义
绑定自定义事件目的:
给子组件传递一个函数,子组件触发这个函数从而修改父组件数据(子-->父)
$event 代表事件触发时传递的第一个参数
事件修饰符
.prevent
.stop
.native 给组件绑定事件时使用的,作用:给组件的第一个元素绑定事件
按键修饰符
@keyup.enter
@keyup.13
触发自定义事件方式:
1. this.$emit('eventName', xxx)
2. this.$listeners.eventName(xxx)
在父组件下面有两个子组件,需要切换显示,切换显示是在子组件完成的
父组件定义切换显示的方法,通过自定义事件绑定给子组件,子组件通过触发自定义事件来切换显示
表格修改功能时,跳转到了新页面进行修改,点击取消要回来展示另外一个组件
使用某个el组件时,他没有click功能,但是我们需要
@click.native
<MyButton @click.native="handleClick" />
// 子
<div>
<button>按钮</button>
</div>
全局事件总线:
1. 使用场景:任意组件
2. 原理:
基于自定义事件
将能定义事件对象(Vue的实例)绑定在Vue的原型对象上
在main.js的new Vue beforeCreate生命周期绑定
在这里绑定所有组件都可以使用
这样所有组件实例对象都能通过原型方式继承到事件对象,从而去绑定或触发事件
理解:
实现任意组件间通信
编码实现:
beforeCreate() {
Vue.prototype.$bus = this
}
分发事件/传递数据的组件: this. b u s . bus. bus.emit(‘eventName’, data)
处理事件/接收数据的组件: this. b u s . bus. bus.on(‘eventName’, (data) => {})
给组件绑定了一个value属性,和input事件
等于是给组件绑定了一个v-bind和自定义事件 props和自定义事件的组合
<template>
<div>
<!-- 给组件绑定了一个value属性,和input事件 -->
<MyInput v-model="msg" />
</div>
</template>
<template>
<input
type="text"
:value="value"
@input="$emit('input', $event.target.value)"
/>
// 一样效果,带解构 但是不会这么去写,这样子就不用接收props
<input
type="text"
v-bind="$attrs"
@input="$emit('input', $event.target.value)"
/>
</template>
<script>
/*
应用场景:表单项
*/
export default {
name: "MyInput",
// props: ["value"],
mounted() {
console.log(this);
},
};
</script>
动态的value属性与原生input事件监听
<input type="text" :value="name2" @input="name2=$event.target.value">
动态的value属性与自定义input事件监听
// 父组件:
<CustomInput :value="name4" @input="name4=$event"/>
// 子组件
props: ['value']
<input type="text" :value="value" @input="$emit('input', $event.target.value)">
绑定一个自定义事件监听, 用来接收子组件分发事件携带的最新数据来更新父组件的数据
<child :money.sync="total"/>
<Child :money="total" @update:money="total=$event"/>
<template>
<div>
<h1><router-link to="/">回到首页</router-link></h1>
<Child :count.sync="count"></Child>
</div>
</template>
<script>
import Child from "./Child";
export default {
name: "Sync",
data() {
return {
count: 1,
};
},
components: {
Child,
},
};
</script>
<template>
<div>
<p>{{ count }}</p>
<button @click="$emit('update:count', count + 1)">点击数字加加</button>
</div>
</template>
<script>
export default {
name: "Child",
props: ["count"],
mounted() {
console.log(this);
},
};
</script>
$attrs
与$listeners
$attrs: 排除props声明, class, style的所有组件标签属性组成的对象
$listeners: 级组件标签绑定的所有自定义事件监听的对象
v-bind: 的特别使用
<div v-bind="{ id: someProp, 'other-attr': otherProp }">div>
v-on: 的特别使用:
<button v-on="{ mousedown: doThis, mouseup: doThat }">button>
一般: v-bind与$attrs
配合使用, v-on与$listeners
配合使用
@dblclick="add2"
绑定是自定义事件监听, 而el-button内部并没处理(没有绑定对应的原生监听, 没有分发自定义事件)
双击时, 不会有响应
@dblclick.native="add2"
绑定的是原生的DOM事件监听, 最终是给组件的根标签a绑定的原生监听
当双击a内部的button能响应, 因为事件有冒泡
<template>
<!-- <Child
v-bind="(person = person)"
@click="handleClick1"
@aaa="handleClick2"
@bbb="handleClick3"
></Child> -->
<!-- <Child
v-bind="person"
@click="handleClick1"
@aaa="handleClick2"
@bbb="handleClick3"
></Child> -->
<Child
:name="person.name"
:age="person.age"
:hobby="person.hobby"
@click="handleClick1"
@aaa="handleClick2"
@bbb="handleClick3"
></Child>
</template>
<script>
import Child from "./Child";
export default {
name: "AttrsAndListeners",
data() {
return {
person: {
name: "小明",
age: 18,
hobby: ["抽烟", "喝酒", "烫头"],
},
};
},
methods: {
handleClick1() {
console.log(123);
},
handleClick2() {
console.log(123);
},
handleClick3() {
console.log(123);
},
},
components: {
Child,
},
};
</script>
<template>
<div>
child
<C v-bind="$attrs" v-on="$listeners"></C>
</div>
</template>
<script>
import C from "./C";
export default {
name: "Child",
components: {
C,
},
mounted() {
console.log(this);
},
};
</script>
<template>
<div>ccc</div>
</template>
<script>
export default {
name: "C",
mounted() {
console.log(this);
},
};
</script>
$children
与$parent
<template>
<div>
mixin
<p>{{ count }}</p>
<button @click="handleClick">Mixin</button>
</div>
</template>
<script>
import mixi from "./mixin";
export default {
name: "Mixin",
mixins: [mixi],
mounted() {
console.log(this);
},
};
</script>
export default {
data() {
return {
count: 0
};
},
methods: {
handleClick() {
this.count++;
}
},
created() {
console.log("mixi created");
},
mounted() {
console.log("mixi mounted");
}
};
<template>
<div>
<A></A>
<B></B>
</div>
</template>
<script>
import A from "./A";
import B from "./B";
export default {
name: "ChildrenAndParent",
data() {
return {
title: "Father",
};
},
components: {
A,
B,
},
mounted() {
console.log(this);
},
};
</script>
<template>
<div>aaa</div>
</template>
<script>
export default {
name: "A",
data() {
return {
title: "AAA",
};
},
mounted() {
console.log(this.$parent.title);
},
};
</script>
用来实现祖孙组件直接通信
在祖组件中通过provide配置向后代组件提供数据
在后代组件中通过inject配置来读取数据
不太建议在应用开发中使用, 一般用来封装vue插件
provide提供的数据本身不是响应式的 ==> 父组件更新了数据, 后代组件不会变化
provide提供的数据对象内部是响应式的 ==> 父组件更新了数据, 后代组件也会变化
element-ui中的Form组件中使用了provide和inject
实现任意组件间通信
Vuex 是一个专为 Vue 应用程序设计的管理多组件共享状态数据的 Vue 插件
任意组件都可以读取到Vuex中store的state对象中的数据
任意组件都可以通过dispatch()或commit()来触发store去更新state中的数据
一旦state中的数据发生变化, 依赖于这些数据的组件就会自动更新
详情见vue分类之vuex
父组件需要向子组件传递标签结构内容
但决定父组件传递怎样标签结构的数据在子组件中
<!: 子组件: >
<slot :row="item" :$index="index">slot>
<!: 父组件: >
<template slot-scope="{row, $index}">
<span>{{$index+1}}span>
<span :style="{color: $index%2===1 ? 'blue' : 'green'}" >{{row.text}}span>
template>
组件写成双标签,里面放入标签数据,那么这个标签数据就会以插槽的方式传递给子组件
// 父组件给子组件传递带数据的标签
<AChild>
<p>hello vue000</p>
<p>hello vue11</p>
<p>{{msg}}</p>
</AChild>
// 子组件使用
// 使用父组件以插槽方式传递的标签数据
<slot></slot>
具名、命名插槽: 给每一个插槽取一个名字
// 具名、命名插槽: 给每一个插槽取一个名字
<BChild>
// 旧语法:slot="名称"
<template slot="header">
<header>头部...{{ title }}</header>
</template>
// 新语法:v-slot:名称
<template v-slot:main>
<main>内容区...</main>
</template>
// 新语法可以简写:#名称
<template #footer>
<footer>底部...</footer>
</template>
</BChild>
<template>
<div>
// 显示头部
// 通过name属性来决定使用哪个具名插槽
<slot name="header"></slot>
<p>---------</p>
// 显示内容区
<slot name="main"></slot>
<p>---------</p>
// 显示底部
<slot name="footer"></slot>
</div>
</template>
<CChild>
// 父组件插槽可以接受子组件通过slot传递的props数据
<template #list="slotProps">
<template v-slot:list="slotProps">
// { person } -> 就是对数据进行解构赋值
<template #list="{ person }">
<template #list="{ person: { name, age } }">
<ul>
<li>姓名:{{ name }}</li>
<li>年龄:{{ age }}</li>
</ul>
</template>
</CChild>
<template>
<div>
// 以标签属性(props)方式传递person数据
<slot name="list" :person="person"></slot>
</div>
</template>
<script>
export default {
name: "CChild",
data() {
return {
person: {
name: "jack",
age: 18,
},
};
},
};
</script>
项目中很少使用,详情见react分类中