1 通信方式
1.1 父向子
props
子修改父的数据:
1. 转存一份在子组件中直接修改(各个子组件中数据独立的)
2. 通过vue自定义事件,通知父组件自己改(各个子组件中数据公用的)
1.2 子向父
vue 自定义事件
1.3 非父子
事件总线、pubsub
1.4 插槽
普通插槽、具名插槽、作用域插槽
1.5 vuex 库
1.6 有路由环境可以通过 url 进行组件间数据传递
1.7 localStorage、sessionStorage
1.8 $event 深入
1. 如果$event出现在dom事件中代表dom事件对象
2. 如果$event出现在vue自定义事件中代表$emit的第二个参数
v-on:事件名.修饰符="回调":
如果修饰符为native 则将vue的自定义事件 转为 原生DOM事件
1.9 v-model
1. 给输入型的dom元素使用: v-model代表数据双向绑定
2. 给vue组件使用: v-model代表子向父的数据传递
<myZJ v-model="msg"></myZJ>
等价于
<myZJ :value="msg" @input="msg = $event"></myZJ>
1.10 .sync 属性修饰符
语法: v-bind:属性名.sync="数据"
组件: <myZJ :xxx.sync="money"></myZJ>
等价于
<myZJ :xxx="money" @update:xxx="money = $event"></myZJ>
1.11 $attrs 与 $listeners
v-bind扩展使用 : v-bind:{a:a,b:b}
$attrs:排除props声明, 排除class, 排除style的所有组件标签属性组成的对象
v-on扩展使用 : v-on:{click:fn,mousemove:fn2}
$listeners:组件标签绑定的所有自定义事件监听的对象
结合 v-bind、v-on 将组件上的非 props、非 class、非 style等属性或事件绑给组件模板中的 DOM 元素。
1.12 $refs $children 与 $parent
$refs : 组件的标记(有可能是dom节点 ; 有可能是组件对象)
$children : 组件的所有子组件
$parent : 组件的父组件
1.13 provide & inject
在生命周期中定义总线事件、触发总线事件太繁琐了
provide、inject 都是配置项:
provide 是一个函数,返回一个对象,传数据
inject 是一个数组,接数据
provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
provide 和 inject 进行数据传递 是不具备响应式的!!!!
顶层组件:
provide(){
return {msg:"xxx"} //传递给子孙组件的数据
}
子孙组件
inject:["msg"] //模板中直接使用msg
1.14 extend
使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数
<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
template: '<p>{
{firstName}} {
{lastName}} aka {
{alias}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')
模板中不需要占位,又相当于一个组件,轻量级。
案例 遮罩层点击出现与消失
1 纯组件方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#loading{
position: fixed;
left: 0;
top:0;
z-index: 9;
width: 100%;
height: 100%;
background: rgba(0,0,0,.7);
display: flex;
justify-content: center;
align-items: center;
color: white;
}
</style>
</head>
<body>
<div id="app">
<button @click="loading = true">click</button>
<v-loading v-show="loading" @hide="loading = false"></v-loading>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
Vue.component("v-loading",{
template:"<div id='loading' @click='$emit(`hide`)'>loading.....</div>"
})
new Vue({
el:"#app",
data(){
return {
loading:false
}
}
})
</script>
</html>
2 自定义指令方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#loading{
position: fixed;
left: 0;
top:0;
z-index: 9;
width: 100%;
height: 100%;
background: rgba(0,0,0,.7);
display: flex;
justify-content: center;
align-items: center;
color: white;
}
</style>
</head>
<body>
<div id="app" v-loading="loading">
<button @click="loading=true">click</button>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
//定义vue指令
Vue.directive("loading",{
update: function (el,binding,vNode) {
//binding.value : loading在data中对应的值
if(binding.value){
//展现遮罩
const divNode = document.createElement("div");
divNode.setAttribute("id","loading");
divNode.innerText = "loading....";
divNode.addEventListener("click",()=>{
vNode.context[binding.expression] = false
})
document.body.appendChild(divNode)
}else{
document.body.removeChild(document.querySelector("#loading"))
}
}
})
new Vue({
el:"#app",
data(){
return {
loading:false
}
}
})
</script>
</html>
el:指令所绑定的元素,可以用来直接操作 DOM。
binding:一个对象,包含以下 property:
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
vnode:Vue 编译生成的虚拟节点。
3 extend 方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#loading{
position: fixed;
left: 0;
top:0;
z-index: 9;
width: 100%;
height: 100%;
background: rgba(0,0,0,.7);
display: flex;
justify-content: center;
align-items: center;
color: white;
}
</style>
</head>
<body>
<div id="mount-point"></div>
</body>
<script src="./js/vue.js"></script>
<script>
var Profile = Vue.extend({
template: '<p>{
{firstName}} {
{lastName}} {
{alias}}</p>',
data: function () {
return {
firstName: 'a',
lastName: 'b',
alias: 'c'
}
}
})
new Profile().$mount('#mount-point')
</script>
</html>
4 js 方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#loading{
position: fixed;
left: 0;
top:0;
z-index: 9;
width: 100%;
height: 100%;
background: rgba(0,0,0,.7);
display: flex;
justify-content: center;
align-items: center;
color: white;
}
</style>
</head>
<body>
<div id="app">
<button @click="clickFn">click</button>
</div>
</body>
<script src="./js/vue.js"></script>
<script>
//extend方法创建组件对象
const Loading = Vue.extend({
template:"<div id='loading' @click='hide'>{
{msg}}</div>",
props:{
msg:{
type:String,
default:"loading..."
}
},
methods:{
hide(){
document.body.removeChild(document.querySelector("#loading"))
}
}
})
//出现遮罩
Vue.prototype.$loading = function (msg) {
//创建一个挂载节点
const divNode = document.createElement("div");
divNode.setAttribute("id","mounted");
document.body.appendChild(divNode);
//创建组件去覆盖挂载节点
new Loading({
props:{
msg:{
type:String,
default:msg
}
},
}).$mount("#mounted")
}
//关闭遮罩
Vue.prototype.$close = function () {
document.body.removeChild(document.querySelector("#loading"))
}
new Vue({
el:"#app",
data(){
return {
loading:false
}
},
methods:{
clickFn(){
//出现遮罩
this.$loading("加载中.....")
//关闭遮罩
setTimeout(()=>{
this.$close()
},3000)
}
}
})
</script>
</html>