Vue 组件间多种通信方式

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>

猜你喜欢

转载自blog.csdn.net/hahayayasan/article/details/113871757