Vue组件化通讯

作者: sunny519111 | 来源:发表于2017-06-14 17:11 被阅读163次

    Vue组件化通讯

    1. Vue的组成文件(.vue)

    分为三部分,分别对应html,js,css

    • <template></template>
    • <script></script>
    • <style></style>

    2. Vue的生命周期函数(watch的时候dom也没有更新)

    1. beforeCreate() 创建数据之前
    2. created() 创建数据 我们在这里的得到我们在data里面创建的数据
    3. beforeMount() // Dom渲染完成前
    4. mounted() //Dom渲染完成
    5. beforeUpdate() // 更新视图 在beforeUpdate触发时,视图已经更新完成
    6. Updated() //更新数据调用的函数、。
    <div id='app'>
      <p>{{msg}}</p>
      <input type='text' v-model='msg'>
    </div>
    
      
    var app = new Vue({
      el: '#app',
      data() {
        return {
          msg: 1
        }
      },
      beforeCreate() {
        console.log('beforeCreate', this.msg); //beforeCreate undefined
        console.log('beforeCreate: ', document.getElementsByTagName('p')[0]) //beforeCreate <p>{{msg}}</p>
      },
      created() {
        // 创建数据
        console.log('created', this.msg); //beforeCreate 1 
        console.log('created: ', document.getElementsByTagName('p')[0]) //beforeCreate <p>{{msg}}</p>
        // 异步处理得到渲染的dom数据
        setTimeout(() => {
          this.msg = 100
          console.log('nextTick', document.getElementsByTagName('p')[0])  
        }, 100)
        // nextTick  <p>100</p>
      },
      beforeMount() {
        console.log('beforeMount', this.msg) //beforeMount 1
        console.log('beforeMount: ', document.getElementsByTagName('p')[0]) // beforeMount  <p>{{msg}}</p>
      },
      mounted() {
        // 渲染dom
        console.log('mounted', this.msg) //mounted 1
        console.log('mounted: ', document.getElementsByTagName('p')[0]) //mounted <p>1</p>
      },
      beforeUpdate() {
        console.log('beforeUpdate', this.msg) //beforeUpdate 100
        console.log('beforeUpdate: ', document.getElementsByTagName('p')[0]) //beforeUpdate <p>100</p>
      },
      updated() {
        console.log('updated', this.msg) // updated 1
        console.log('updated: ', document.getElementsByTagName('p')[0]) // updated <p>100</p>
      }
    })
    

    生命周期参考链接

    3. export default

    每一个模块都是自己的作用域,相应的属性来处理数据和函数

    1. data(声明数据,可以是函数和属性)
    • 类型Object | Function
    • 组件只接受函数
       // 对象的形式
       export default{
         data: {
           a:1
         }
       }
       // 函数的形式
       export default{
         data(){
           return {
             a: 1
           }
         }
       }
    
    1. methods(一些指令和其他属性的调用方法)
      • 不要用箭头函数来写里面的函数
      • this指向Vue的实例
     export default{
       methods: {
         plus() {
           this.a++
         }
       }
     }
    
    1. components (组件化定义)
      • 类型: Object
      • 自定义元素,增加代码的复用性
     // 当我们引用一个.vue文件的时候,就像使用这个文件来充当我们主体的一部分
     <div>
        <hello></hello>  
     </div>
    
     import hello from './hello.vue'
     export default {
       components: {
         hello
       }
     }
    
    1. computed(计算属性)

      • 计算属性的结果会被缓存,依赖的数据发生变化才会重新渲染
      • 注意计算属性和methods,watch的区别
      {{this.total}} //[3,4]
      <button @click='add'>添加数据</button> //点击会更新this.total    
      
      export default {
        data: () => ({
          a: 1,
          b: [2,3]
        }),
        methods: {
          add(){
            this.b.push(8);
          }
        },
        computed: {
          total(){
            return this.b.map((item)=>{
              return item+this.a
            })
          }
        }
      }
      
    2. watch(监听对应的数据)

      • 键值对。键是我们需要监督的数据,值是相应的回调函数
      • 回调函数接受2个参数,新的值和旧的值(对于数组和对象不会出现旧值,对于简单的数据会出现旧值)
      • 监听对象的内部值变化,需要添加deep:true(数组不用)
      // 点击后相应的变化
      data(){
          return {
            a: 1,
            b: [2,4,6],
            c:{name:'hcc',age:22}
          }
        },
      methods: {
         add(){
            this.a++
            this.b.push(8)
            this.c.name = 'yx'
          }
        },
      watch: {
          b: function(val, oldVal){
             console.log('new', val) //[2,4,6,8]
             console.log('new', oldVal) //[2,4,6,8]
          },
          a: function(val, oldVal){
            console.log(val);  //2
            console.log(oldVal); //1
          },
          c:{
            handler(val){
              console.log(val); //{name: 'yx',age: 22}
            } 
          }
      },
      
    3. props(用于接受父组件传来的数据)

      • 规定和接受父组件的数据
      • 单向数据流,子组件不能修改传递过来的数据
      • 对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
      • 可以规定接受的数据类型和默认值,如果是对象和数组,默认值导出是一个函数
      // 父组件
      <hello :formParent='num'></hello>  //html
      components: {
        hello
      },
      data(){
        return {
          num: 3
        }
      }
      
      //子组件
      //1. 数组规定接受的数据
      props: ['hello']
      //2. 验证的方式
      props:{
        hello: Number,
        hello: [String, Number],
        hello: {
          type: Object,
          default(){
            return {message: 'hello'}
          }
        }
      }
      
    4. v-on和v-emit(子组件向父元素传递数据)

      • vm.$emit: 子元素向父元素定义讯号和传递数据

        this.$emit('规定的讯号名称', '想传递给父元素的数据')

      • vm.$on: 监听讯号,并触发相应的函数(函数内部不用传参)

        @'规定的讯号名称'='调用自己组件的方法并可以接受传递的参数'

      // 子组件
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      },
      methods: {
        change(){
          this.$emit('sendMsg',this.msg)  //把msg传递给父组件
        }
      }
      
      // 父组件
      // 引入子组件,并定义components
      components: {
        hello
      },
      methods: {
        show(msg){     // 这里接受子组件传递的参数
          console.log(msg);
        }
      }
      
      <hello @sendMsg='show'></hello>  // 这里不用传递参数,不然会覆盖子元素传递的参数
      
    5. ref(用来获取dom和子组件)

      • 可以用来操作dom<p ref="p">hello</p>

      • 可以用来组件中的通讯

      • 在组件中使用的this.refs是一个对象,包含了所有的绑定了的dom和子组件

        // html 
         <h1 ref="myElement">这是一个dom元素</h1>  //dom元素
         <hello :propnum="propnum" :obj='d' @getson='getMsg' ref='child'></hello> // 子组件
         >-- 组件中this.refs =>  {myElement: h1, child: VueComponent}
        
        // 运用(在父元素中调用子元素的方法)
        // html 
        <hello ref='child'></hello> 
        // 子元素hello
         methods: {
           change() {
             this.$emit('getson',this.msg)
             this.obj.name = 'yx'
           },
             drop(el) {
               el.style.background = 'red';
             }
         },
           
        // 父元素
        methods: {
          add() {
            console.log(this.refs); //{child: VueComponent}
            this.$refs.child.drop('这里传递父元素的dom节点')
          }
        }
        
        //如果有一个需求是,一个父元素有2个子组件,其中一个子组件的方法要调用另一个子组件的dom元素
        1. 一个子组件需要向父组件发送元素this.$emit('方法名',dom)
        2. 父元素接受到子组件的传递得到对应dom
        3. 父元素通过this.$refs调用对应的另一个子组件的方法并传入参数
        // 子元素hello和world
          <div class="world">
            <h1 ref="world">这是world的dom元素</h1>
            <button @click='send'>给父元素传递dom</button>
          </div>
          methods: {
            send(){
              this.$emit('give',this.$refs.world); //给父元素发送dom
          }  
          <div class='hello'>
            <button>改变dom</button>
          </div>  
          methods: {
            changeDom(target){
              console.log(target)
            }
          }
            
          // 父元素
          <world @give='父亲自己的方法'></world>
          <hello ref='helloChild'></hello>
          methods: {
            // 这里接受子元素传递过来的dom元素
            '父亲自己的方法'(target) {
              this.refs.helloChild.changeDom(target)  //调用另一个子元素的方法,并把dom传递过去
            }
          }
        
    6. vm.nextTick(callback)

      • 下次dom更新循环结束后执行对应的回调函数

      • 在修改数据之后立即使用这个方法,可以获取更新后的DOM结构

    • 使用场景
      • 在 Vue 生命周期的 created() 钩子函数进行的 DOM 操作一定要放在 Vue.nextTick() 的回调函数中。原因是什么呢,原因是
        在 created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的 js 代码放进 Vue.nextTick() 的回调函数中。
        与之对应的就是 mounted 钩子函数,因为该钩子函数执行时所有的 DOM 挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
      • 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的 DOM 结构的时候,这个操作都应该放进 Vue.nextTick() 的回调函数中。
    // 需求一,如果我们想异步请求数据后,在钩子函数mounted之前只用对应的dom
    // 思路: 通过异步等dom更新后,然后获得对应的dom
    <template>
       <h1 ref='title'>{{b}}</h1>
    </template>
    <script>
    export default {
     data() {
          b: 'hello nextTick'
      },
      create() {
        console.log(this.refs.title)  // undefined
      }, 
    // 这样可以获得对应的dom (当dom全部渲染后再执行console.log())
    //  create() {
    //   this.$nextTick(()=>{
    //        console.log(this.refs.title);  // <h1>hello nextTick</h1>(输出在mounted的后面)
    //    })
    //  }, 
      mounted() {
        console.log(this.refs.title)  // <h1>hello nextTick</h1>
      }
    }
    </script>
    

    相关文章

      网友评论

        本文标题:Vue组件化通讯

        本文链接:https://www.haomeiwen.com/subject/kmceqxtx.html