Vue組件化通訊

Vue組件化通訊

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

分為三部分,分別對(duì)應(yīng)html,js,css

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

2. Vue的生命周期函數(shù)(watch的時(shí)候dom也沒(méi)有更新)

  1. beforeCreate() 創(chuàng)建數(shù)據(jù)之前
  2. created() 創(chuàng)建數(shù)據(jù) 我們?cè)谶@里的得到我們?cè)赿ata里面創(chuàng)建的數(shù)據(jù)
  3. beforeMount() // Dom渲染完成前
  4. mounted() //Dom渲染完成
  5. beforeUpdate() // 更新視圖 在beforeUpdate觸發(fā)時(shí),視圖已經(jīng)更新完成
  6. Updated() //更新數(shù)據(jù)調(diào)用的函數(shù)、。
<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() {
    // 創(chuàng)建數(shù)據(jù)
    console.log('created', this.msg); //beforeCreate 1 
    console.log('created: ', document.getElementsByTagName('p')[0]) //beforeCreate <p>{{msg}}</p>
    // 異步處理得到渲染的dom數(shù)據(jù)
    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

每一個(gè)模塊都是自己的作用域,相應(yīng)的屬性來(lái)處理數(shù)據(jù)和函數(shù)

  1. data(聲明數(shù)據(jù),可以是函數(shù)和屬性)
  • 類型Object | Function
  • 組件只接受函數(shù)
   // 對(duì)象的形式
   export default{
     data: {
       a:1
     }
   }
   // 函數(shù)的形式
   export default{
     data(){
       return {
         a: 1
       }
     }
   }
  1. methods(一些指令和其他屬性的調(diào)用方法)
    • 不要用箭頭函數(shù)來(lái)寫(xiě)里面的函數(shù)
    • this指向Vue的實(shí)例
 export default{
   methods: {
     plus() {
       this.a++
     }
   }
 }
  1. components (組件化定義)
    • 類型: Object
    • 自定義元素,增加代碼的復(fù)用性
 // 當(dāng)我們引用一個(gè).vue文件的時(shí)候,就像使用這個(gè)文件來(lái)充當(dāng)我們主體的一部分
 <div>
    <hello></hello>  
 </div>

 import hello from './hello.vue'
 export default {
   components: {
     hello
   }
 }
  1. computed(計(jì)算屬性)

    • 計(jì)算屬性的結(jié)果會(huì)被緩存,依賴的數(shù)據(jù)發(fā)生變化才會(huì)重新渲染
    • 注意計(jì)算屬性和methods,watch的區(qū)別
    {{this.total}} //[3,4]
    <button @click='add'>添加數(shù)據(jù)</button> //點(diǎn)擊會(huì)更新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(監(jiān)聽(tīng)對(duì)應(yīng)的數(shù)據(jù))

    • 鍵值對(duì)。鍵是我們需要監(jiān)督的數(shù)據(jù),值是相應(yīng)的回調(diào)函數(shù)
    • 回調(diào)函數(shù)接受2個(gè)參數(shù),新的值和舊的值(對(duì)于數(shù)組和對(duì)象不會(huì)出現(xiàn)舊值,對(duì)于簡(jiǎn)單的數(shù)據(jù)會(huì)出現(xiàn)舊值)
    • 監(jiān)聽(tīng)對(duì)象的內(nèi)部值變化,需要添加deep:true(數(shù)組不用)
    // 點(diǎn)擊后相應(yīng)的變化
    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(用于接受父組件傳來(lái)的數(shù)據(jù))

    • 規(guī)定和接受父組件的數(shù)據(jù)
    • 單向數(shù)據(jù)流,子組件不能修改傳遞過(guò)來(lái)的數(shù)據(jù)
    • 對(duì)象和數(shù)組是引用類型,指向同一個(gè)內(nèi)存空間,如果 prop 是一個(gè)對(duì)象或數(shù)組,在子組件內(nèi)部改變它會(huì)影響父組件的狀態(tài)。
    • 可以規(guī)定接受的數(shù)據(jù)類型和默認(rèn)值,如果是對(duì)象和數(shù)組,默認(rèn)值導(dǎo)出是一個(gè)函數(shù)
    // 父組件
    <hello :formParent='num'></hello>  //html
    components: {
      hello
    },
    data(){
      return {
        num: 3
      }
    }
    
    //子組件
    //1. 數(shù)組規(guī)定接受的數(shù)據(jù)
    props: ['hello']
    //2. 驗(yàn)證的方式
    props:{
      hello: Number,
      hello: [String, Number],
      hello: {
        type: Object,
        default(){
          return {message: 'hello'}
        }
      }
    }
    
  4. v-on和v-emit(子組件向父元素傳遞數(shù)據(jù))

    • vm.$emit: 子元素向父元素定義訊號(hào)和傳遞數(shù)據(jù)

      this.$emit('規(guī)定的訊號(hào)名稱', '想傳遞給父元素的數(shù)據(jù)')

    • vm.$on: 監(jiān)聽(tīng)訊號(hào),并觸發(fā)相應(yīng)的函數(shù)(函數(shù)內(nèi)部不用傳參)

      @'規(guī)定的訊號(hào)名稱'='調(diào)用自己組件的方法并可以接受傳遞的參數(shù)'

    // 子組件
    data () {
      return {
        msg: 'Welcome to Your Vue.js App'
      }
    },
    methods: {
      change(){
        this.$emit('sendMsg',this.msg)  //把msg傳遞給父組件
      }
    }
    
    // 父組件
    // 引入子組件,并定義components
    components: {
      hello
    },
    methods: {
      show(msg){     // 這里接受子組件傳遞的參數(shù)
        console.log(msg);
      }
    }
    
    <hello @sendMsg='show'></hello>  // 這里不用傳遞參數(shù),不然會(huì)覆蓋子元素傳遞的參數(shù)
    
  5. ref(用來(lái)獲取dom和子組件)

    • 可以用來(lái)操作dom<p ref="p">hello</p>

    • 可以用來(lái)組件中的通訊

    • 在組件中使用的this.refs是一個(gè)對(duì)象,包含了所有的綁定了的dom和子組件

      // html 
       <h1 ref="myElement">這是一個(gè)dom元素</h1>  //dom元素
       <hello :propnum="propnum" :obj='d' @getson='getMsg' ref='child'></hello> // 子組件
       >-- 組件中this.refs =>  {myElement: h1, child: VueComponent}
      
      // 運(yùn)用(在父元素中調(diào)用子元素的方法)
      // 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節(jié)點(diǎn)')
        }
      }
      
      //如果有一個(gè)需求是,一個(gè)父元素有2個(gè)子組件,其中一個(gè)子組件的方法要調(diào)用另一個(gè)子組件的dom元素
      1. 一個(gè)子組件需要向父組件發(fā)送元素this.$emit('方法名',dom)
      2. 父元素接受到子組件的傳遞得到對(duì)應(yīng)dom
      3. 父元素通過(guò)this.$refs調(diào)用對(duì)應(yīng)的另一個(gè)子組件的方法并傳入?yún)?shù)
      // 子元素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); //給父元素發(fā)送dom
        }  
        <div class='hello'>
          <button>改變dom</button>
        </div>  
        methods: {
          changeDom(target){
            console.log(target)
          }
        }
          
        // 父元素
        <world @give='父親自己的方法'></world>
        <hello ref='helloChild'></hello>
        methods: {
          // 這里接受子元素傳遞過(guò)來(lái)的dom元素
          '父親自己的方法'(target) {
            this.refs.helloChild.changeDom(target)  //調(diào)用另一個(gè)子元素的方法,并把dom傳遞過(guò)去
          }
        }
      
  6. vm.nextTick(callback)

    • 下次dom更新循環(huán)結(jié)束后執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)

    • 在修改數(shù)據(jù)之后立即使用這個(gè)方法,可以獲取更新后的DOM結(jié)構(gòu)

  • 使用場(chǎng)景
    • 在 Vue 生命周期的 created() 鉤子函數(shù)進(jìn)行的 DOM 操作一定要放在 Vue.nextTick() 的回調(diào)函數(shù)中。原因是什么呢,原因是
      在 created() 鉤子函數(shù)執(zhí)行的時(shí)候 DOM 其實(shí)并未進(jìn)行任何渲染,而此時(shí)進(jìn)行 DOM 操作無(wú)異于徒勞,所以此處一定要將 DOM 操作的 js 代碼放進(jìn) Vue.nextTick() 的回調(diào)函數(shù)中。
      與之對(duì)應(yīng)的就是 mounted 鉤子函數(shù),因?yàn)樵撱^子函數(shù)執(zhí)行時(shí)所有的 DOM 掛載和渲染都已完成,此時(shí)在該鉤子函數(shù)中進(jìn)行任何DOM操作都不會(huì)有問(wèn)題 。
    • 在數(shù)據(jù)變化后要執(zhí)行的某個(gè)操作,而這個(gè)操作需要使用隨數(shù)據(jù)改變而改變的 DOM 結(jié)構(gòu)的時(shí)候,這個(gè)操作都應(yīng)該放進(jìn) Vue.nextTick() 的回調(diào)函數(shù)中。
// 需求一,如果我們想異步請(qǐng)求數(shù)據(jù)后,在鉤子函數(shù)mounted之前只用對(duì)應(yīng)的dom
// 思路: 通過(guò)異步等dom更新后,然后獲得對(duì)應(yīng)的dom
<template>
   <h1 ref='title'>{{b}}</h1>
</template>
<script>
export default {
 data() {
      b: 'hello nextTick'
  },
  create() {
    console.log(this.refs.title)  // undefined
  }, 
// 這樣可以獲得對(duì)應(yīng)的dom (當(dāng)dom全部渲染后再執(zhí)行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>

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容