• Vue组件通信应用实践总结


    【1】 组件通信的5种方式

    props
    vue的自定义事件
    pubsub第三方库
    slot
    vuex
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ① props

    父子组件间通信的基本方式
    属性值的2大类型: 
     一般: 父组件-->子组件
     函数: 子组件-->父组件
    隔层组件间传递: 必须逐层传递(麻烦)
    兄弟组件间: 必须借助父组件(麻烦)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ② vue自定义事件

    子组件与父组件的通信方式
    用来取代function props
    不适合隔层组件和兄弟组件间的通信
    
    • 1
    • 2
    • 3

    ③ pubsub第三方库(消息订阅与发布)

    适合于任何关系的组件间通信

    ④ slot

    通信是带数据的标签,注意: 标签是在父组件中解析。

    ⑤ vuex

    多组件共享状态(数据的管理),组件间的关系也没有限制。功能比pubsub强大, 更适用于vue项目

    【2】组件引入与组件传值

    ① 父页面

    <template>
      <div class="todo-container">
        <div class="todo-wrap">
        
          <TodoList :todos="todos"/>
              
          <TodoFooter :todos="todos" :deleteCompleteTodos="deleteCompleteTodos" :selectAll="selectAll"/>
        div>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ② 脚本

    父页面需要引入并声明组件:

    <script>
    //import引入组件
      import TodoHeader from './components/TodoHeader.vue'
      import TodoList from './components/TodoList.vue'
      import TodoFooter from './components/TodoFooter.vue'
      import storageUtils from './utils/storageUtils'
    
      export default {
      //声明组件
        components: {
          TodoHeader,
          TodoList,
          TodoFooter
        }
        //数据
        data () {
          return {
            todos: storageUtils.readTodos()
          }
        },
        methods: {
          addTodo (todo) {
            this.todos.unshift(todo)
          },
    
          deleteTodo (index) {
            this.todos.splice(index, 1)
          },
    
          // 删除所有已完成的
          deleteCompleteTodos () {
            this.todos = this.todos.filter(todo => !todo.complete)
          },
    
          // 全选/全不选
          selectAll (isSelectAll) {
            this.todos.forEach(todo => {
              todo.complete = isSelectAll
            })
          }
        }
      }
    </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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    export 用来导出模块,Vue 的单文件组件通常需要导出一个对象,这个对象是 Vue 实例的选项对象,以便于在其它地方可以使用 import 引入。而 new Vue() 相当于一个构造函数,在入口文件 main.js 构造根组件的同时,如果根组件还包含其它子组件,那么 Vue 会通过引入的选项对象构造其对应的 Vue 实例,最终形成一棵组件树。

    使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名。

    default只能有一个值,所以一个文件内不能有多个export defaul。

    export default输出一个叫做default的变量,然后系统允许你为它取任意名字。所以可以为import的模块起任何变量名,且不需要用大括号包含

    export default写法顺序

    name
    components
    props
    data
    created
    methods
    mounted
    computed
    watch
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ③ 子页面

    子页面通过props接受父组件的传值:

    <template>
      <div class="todo-footer">
        <label>
          <input type="checkbox" v-model="checkAll"/>
        label>
        <span>
              <span>已完成{{completeSize}}span> / 全部{{todos.length}}
            span>
        <button class="btn btn-danger" v-show="completeSize" @click="deleteAllCompleted">清除已完成任务button>
      div>
    template>
    
    <script>
      export default {
      //接收父组件的值传递与方法传递
        props: {
          todos: Array,
          deleteCompleteTodos: Function,
          selectAll: Function
        },
    
        computed: {
          completeSize () {
            return this.todos.reduce((preTotal, todo) => preTotal + (todo.complete?1:0) ,0)
          },
    
          checkAll: {
            get () { // 决定是否勾选
              return this.completeSize===this.todos.length && this.completeSize>0
            },
    
            set (value) {// 点击了全选checkbox  value是当前checkbox的选中状态(true/false)
              this.selectAll(value)
            }
          },
        },
    
        methods: {
          deleteAllCompleted () {
            if(window.confirm('确定清除已完成的吗?')) {
              this.deleteCompleteTodos()
            }
          }
        }
      }
    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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    【3】 props的三种写法

    ① 第一种简写

     export default {
        // 声明接收标签属性
        props: ['todos'], // 会成为当前组件对象的属性, 可以在模板中直接访问, 也可以通过this来访问
        components: {
          TodoItem
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ② 第二种写法

     export default {
        props: {// 指定属性名和属性值的类型
          todo: Object,
          index: Number
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第三种复杂写法

     export default {
        props: {
          todo: {
    		type:Function,
    		required:true,
    		 default: function () {
    	        return { message: 'hello' }
    	      },
    		 validator: function (value) {
    		        // 这个值必须匹配下列字符串中的一个
    		        return ['success', 'warning', 'danger'].indexOf(value) !== -1
    		      }
    			},
          index: Number
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    type:可以是下列原生构造函数中的一种:String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定义构造函数、或上述内容组成的数组

    会检查一个 prop 是否是给定的类型,否则抛出警告。Prop 类型的更多信息如下所示:

    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object,
      callback: Function,
      contactsPromise: Promise // or any other constructor
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    default:any

    为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回。

    required:Boolean

    定义该 prop 是否是必填项。在非生产环境中,如果这个值为 truthy 且该 prop 没有被传入的,则一个控制台警告将会被抛出。

    validator:Function

    自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 falsy 的值 (也就是验证失败),一个控制台警告将会被抛出。你可以在这里查阅更多 prop 验证的相关信息。

    props更多文档参考https://cn.vuejs.org/v2/guide/components-props.html


    【4】组件通信之消息发布订阅

    消息订阅与发布(PubSubJS 库),此方式可实现任意关系组件间通信(数据)。

    需要先安装PubSubJS 库,npm install --save pubsub-js

    然后引入:

     import PubSub from 'pubsub-js'
    
    • 1

    ① 发布消息

    PubSub.publish('msg', data)
    
    • 1

    触发事件(发布消息)

    DOM 事件: 用户在浏览器上对应的界面上做对应的操作
    自定义: 编码手动触发
    
    • 1
    • 2

    实例如下:

     deleteItem () {
            // this.deleteTodo(this.index)
            // 发布消息(deleteTodo)
            PubSub.publish('deleteTodo', this.index)
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ② 订阅消息

    PubSub.subscribe('msg', function(msg, data){})
    
    • 1

    绑定事件监听(订阅消息)

    目标: 标签元素<button>
    事件名(类型): click/focus
    回调函数: function(event){}
    
    • 1
    • 2
    • 3

    实例如下:

        mounted () {
          // 绑定自定义事件(addTodo)监听
          this.$refs.header.$on('addTodo',  this.addTodo)
          // 订阅消息(deleteTodo)
          PubSub.subscribe('deleteTodo', (msg, index) => {
            this.deleteTodo(index)
          })
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    【5】组件间通信之slot

    slot主要用于父组件向子组件传递标签数据。
    父组件实例

    <TodoFooter>
    	<input slot="checkAll" type="checkbox" v-model="checkAll" />
    	<span slot="size">已完成{{completeSize}} / 全部{{todos.length}}span>
    	<button slot="delete" class="btn btn-danger" v-show="completeSize" @click="deleteAllCompleted" >清除已完成任务button>
    TodoFooter>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    子组件实例

    <template>
      <div class="todo-footer">
        <label>
          
          <slot name="checkAll">slot>
        label>
    
        <span>
          <slot name="size">slot>
         {completeSize}} / 全部{{todos.length}}-->
        span>
    
        <slot name="delete">slot>
       
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    【6】自定义事件

    ① v-on指令监听事件

    可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。v-on:事件名, 可以缩写为: @事件名

    事件修饰符

    在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

    为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

    .stop
    .prevent
    .capture
    .self
    .once
    .passive
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    代码示例如下

    
    <a v-on:click.stop="doThis">a>
    
    
    <form v-on:submit.prevent="onSubmit">form>
    
    
    <a v-on:click.stop.prevent="doThat">a>
    
    
    <form v-on:submit.prevent>form>
    
    
    
    <div v-on:click.capture="doThis">...div>
    
    
    
    <div v-on:click.self="doThat">...div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ② 自定义事件监听

    第一种方式

    #给TodoHeader 标签对象绑定addTodo事件监听
    <TodoHeader @addTodo="addTodo"/>
    
    • 1
    • 2

    那么子组件如何触发事件呢?

    //this.addTodo(todo)---原先使用props通信
    
    /*触发自定义事件: addTodo*/
    this.$emit('addTodo', todo)
    
    • 1
    • 2
    • 3
    • 4

    第二种方式

    <TodoHeader ref="header"/>
    
    mounted () {
      // 绑定自定义事件(addTodo)监听
      this.$refs.header.$on('addTodo',  this.addTodo)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    需要注意的是上面函数传递方式只适用于父-子,也就是A-B;A-B-C则不适用。

  • 相关阅读:
    手写Promise
    简单写个JS插件替换网页上的文本
    Qt中显示摄像头数据(V4L2三)
    Pick-a-Pic:An open dataset of user preferences for text-to-image generation
    基于SSM框架的校园疫情防控健康打卡系统
    高级程序员项目经理写好代码必备的三条基本素质;以及代码的现象和本质问题解读;
    【MySQL基础|第三篇】--- 详谈SQL中的DQL语句
    Web3钱包和身份验证:安全和去中心化的新标准
    1.12 进程注入ShellCode套接字
    使用基于Web的交互式开发工具Zeppelin
  • 原文地址:https://blog.csdn.net/J080624/article/details/133605163