溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析

發(fā)布時間:2022-08-08 17:42:01 來源:億速云 閱讀:206 作者:iii 欄目:編程語言

這篇“VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析”文章吧。

VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析

vue2.0 響應(yīng)式

1. 對象的響應(yīng)式

1.1 Object.defineProperty

Object.defineProperty(obj, prop, descriptor)方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性,并返回此對象。

obj——要定義屬性的對象
prop——要定義或修改的屬性的名稱或Symbol
descriptor——對象,要定義或修改的屬性描述符

// descriptor{
  value: undefined, // 屬性的值
  get: undefined,   // 獲取屬性值時觸發(fā)的方法
  set: undefined,   // 設(shè)置屬性值時觸發(fā)的方法
  writable: false,  // 屬性值是否可修改,false不可改
  enumerable: false, // 屬性是否可以用for...in 和 Object.keys()枚舉
  configurable: false  // 該屬性是否可以用delete刪除,false不可刪除,為false時也不能再修改該參數(shù)}

通過賦值操作添加的普通屬性是可枚舉的,在枚舉對象屬性時會被枚舉到(for…in 或 Object.keys 方法),可以改變這些屬性的值,也可以刪除這些屬性。這個方法允許修改默認的額外選項(或配置)。
而默認情況下,使用 Object.defineProperty() 添加的屬性值是不可修改(immutable)的。
示例:

const a = {b : 1}console.log(Object.getOwnPropertyDescriptor(a, 'b'))// {value: 1, writable: true, enumerable: true, configurable: true}Object.defineProperty(a, 'c', {value: '2'})console.log(Object.getOwnPropertyDescriptor(a, 'c'))// {value: '2', writable: false, enumerable: false, configurable: false}a.c = 3console.log(a.c)// 2Object.defineProperty(a, 'c', {value: '4'})console.log(a.c)// error: Uncaught TypeError: Cannot redefine property: c
1.2 set和get
// 模擬vue響應(yīng)式過程const app = document.getElementById('app')const data = {
	a: {
	  b: {
	    c: 1
	  }
	}}function render () {
  const virtualDom = `這是我的內(nèi)容${data.a.b.c}`		
  app.innerHTML = virtualDom}function observer (obj) {
  let value  for (const key in obj) {  // 遞歸設(shè)置set和get
    value = obj[key]
    if (typeof value === 'object'){
      arguments.callee(value)
    } else {
      Object.defineProperty(obj, key, {
        get: function(){
          return value        },
        set: function(newValue){
          value = newValue          render()
        }
      })
    }
  }}render()observer(data)setTimeout(() => {
  data.a.b.c = 22}, 2000)setTimeout(() => {
  data.a.b.c = 88}, 5000)

上述方法實現(xiàn)了數(shù)據(jù)的響應(yīng),但存在很大的問題,我們觸發(fā)一次set,就需要整個頁面重新渲染,然而這個值可能只在某一個組件中使用了。
VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析

所以將get和set優(yōu)化:

Object.defineProperty(data, key, {
  get: function(){
    dep.depend() // 這里進行依賴收集
    return value  },
  set: function(newValue){
    value = newValue    // render()
    dep.notify()  // 這里進行virtualDom更新,通知需要更新的組件render
  }});

dep是Vue負責管理依賴的一個類

補充: Vue 無法檢測 property 的添加或移除。由于 Vue 會在初始化實例時對 property 執(zhí)行 getter/setter 轉(zhuǎn)化,所以 property 必須在 data 對象上存在才能讓 Vue 將它轉(zhuǎn)換為響應(yīng)式的

const vm = new Vue({
	data: {
		a: 1
	}})// vm.a是響應(yīng)式的vm.b = 2// vm.b是非響應(yīng)式的

2. 數(shù)組的響應(yīng)式

vue 中處理數(shù)組的變化,直接通過下標觸發(fā)視圖的更改,只能使用push、shift等方法,而數(shù)組不能使用Object.defineProperty()
其實 Vue用裝飾者模式來重寫了數(shù)組這些方法

Object.create(proto,[propertiesObject]) 方法是創(chuàng)建一個新對象,使用現(xiàn)有的對象來提供新創(chuàng)建的對象的__proto__

proto——新創(chuàng)建對象的原型對象;
propertiesObject ——選填,類型是對象,如果該參數(shù)被指定且不為 undefined,該傳入對象的自有可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)將為新創(chuàng)建的對象添加指定的屬性值和對應(yīng)的屬性描述符

const a = {}// 相當于const a = Object.create(Object.prototype)const person = {
  isHuman: false,
  printIntroduction: function () {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }};const me = Object.create(person);me.name = 'Matthew'; // "name" is a property set on "me", but not on "person"me.isHuman = true; // inherited properties can be overwrittenme.printIntroduction();// expected output: "My name is Matthew. Am I human? true"
const o = Object.create(Object.prototype, {
  foo: { // foo會成為所創(chuàng)建對象的數(shù)據(jù)屬性
    writable:true,
    configurable:true,
    value: "hello"
  },
  bar: { // bar會成為所創(chuàng)建對象的訪問器屬性
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }});console.log(o) // {foo: 'hello'}

vue中的裝飾者模式

const arraypro = Array.prototype    // 獲取Array的原型const arrob = Object.create(arraypro) // 用Array的原型創(chuàng)建一個新對象,arrob.__proto__ === arraypro,免得污染原生Array;const arr=['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']   // 需要重寫的方法arr.forEach(function(method) {
  arrob[method] = function () {
    arraypro[method].apply(this, arguments) // 重寫時先調(diào)用原生方法
    dep.notify() // 并且同時更新
  }})// 對于用戶定義的數(shù)組,手動將數(shù)組的__proto__指向我們修改過的原型const a = [1, 2, 3]a.__proto__ = arrob

上面對于新對象arrob的方法,我們是直接賦值的,這樣會有一個問題,就是用戶可能會不小心改掉我們的對象,所以我們可以用到我們前面講到的Object.defineProperty來規(guī)避這個問題,我們創(chuàng)建一個公用方法def專門來設(shè)置不能修改值的屬性

function def (obj, key, value) {
  Object.defineProperty(obj, key, {
    // 這里我們沒有指定writeable,默認為false,即不可修改
    enumerable: true,
    configurable: true,
    value: value,
  });}// 數(shù)組方法重寫改為arr.forEach(function(method){
  def(arrob, method, function () {
    arraypro[method].apply(this, arguments)  // 重寫時先調(diào)用原生方法
    dep.notify()// 并且同時更新
  })})

3. 補充:對象的數(shù)據(jù)屬性和訪問器屬性

數(shù)據(jù)屬性: 它包含的是一個數(shù)據(jù)值的位置,在這可以對數(shù)據(jù)值進行讀寫

數(shù)據(jù)屬性的四個描述符:


含義
configurable表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或能否把屬性修改為訪問器屬性,默認為true
enumerable表示能否通過for-in循環(huán)返回屬性,默認為true
writable表示能否修改屬性的值,默認為true
value包含該屬性的數(shù)據(jù)值,默認為undefined

訪問器屬性: 這個屬性不包含數(shù)據(jù)值,包含的是一對get和set方法,在讀寫訪問器屬性時,就是通過這兩個方法來進行操作處理的。

訪問器屬性的四個描述符:


含義
configurable表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或能否把屬性修改為訪問器屬性,默認為false
enumerable表示能否通過for-in循環(huán)返回屬性,默認為false
get在讀取屬性時調(diào)用的函數(shù),默認值為undefined
set在寫入屬性時調(diào)用的函數(shù),默認值為undefined

vue3.0數(shù)據(jù)響應(yīng)

vue3.0的響應(yīng)式和vue2.0響應(yīng)式原理類似,都是在get中收集依賴,在set中通知依賴更新視圖,但vue3.0使用了es6新增的proxy來代替Object.defineProperty()

proxy相對于Object.defineProperty()的好處:

  1. Object.defineProperty需要指定對象和屬性,對于多層嵌套的對象需要遞歸監(jiān)聽,Proxy可以直接監(jiān)聽整個對象,不需要遞歸;

  2. Object.defineProperty的get方法沒有傳入?yún)?shù),如果我們需要返回原值,需要在外部緩存一遍之前的值,Proxy的get方法會傳入對象和屬性,可以直接在函數(shù)內(nèi)部操作,不需要外部變量;

  3. set方法也有類似的問題,Object.defineProperty的set方法傳入?yún)?shù)只有newValue,也需要手動將newValue賦給外部變量,Proxy的set也會傳入對象和屬性,可以直接在函數(shù)內(nèi)部操作;

  4. new Proxy()會返回一個新對象,不會污染源原對象

  5. Proxy可以監(jiān)聽數(shù)組,不用單獨處理數(shù)組

proxy劣勢: vue3.0將放棄對低版本瀏覽器的兼容(兼容版本ie11以上)

這樣上邊的observe方法就可以優(yōu)化成:

function observer () {
  var self = this;
  data = new Proxy(data, {
    get: function(target, key){
      dep.depend() // 這里進行依賴收集
      return target[key]
    },
    set: function(target, key, newValue){
      target[key] = newValue;
      // render()
	  dep.notify()  // 這里進行virtualDom更新,通知需要更新的組件render
    }
  });}

模塊化(組件化)開發(fā)

按照功能(或按照復用性)把一個頁面拆成各個板塊(模塊),每一個模塊都是一個單獨的文件(單獨的組件),最后把各個模塊(組件)拼在一起即可??!

目的 :方便團隊協(xié)作開發(fā) 實現(xiàn)復用

組件分類

功能型組件「UI組件庫中提供的一般都是功能型組件:element/iview/antdv/vant/cube..」

  • + 一般UI組件庫提供的功能組件就夠用了

  • + 偶爾UI組件庫中不存在的,才需要自己封裝「難點」

  • + 我們經(jīng)常會把功能型組件進行二次封裝(結(jié)合自己項目的業(yè)務(wù)邏輯)「特殊亮點」

業(yè)務(wù)型組件

  • + 通用業(yè)務(wù)型組件「好多頁面都需要用到的,我們把其封裝成為公共的組件」

  • + 普通組件

以后開發(fā)項目,拿到設(shè)計稿的第一件事情:劃分組件「按照功能版塊劃分、本著復用性原則,拆的越細越好(這樣才能更好的實現(xiàn)復用)」

組件的創(chuàng)建及使用

創(chuàng)建一個 Xxx.vue 就是創(chuàng)建一個vue組件{局部組件、私有組件},組件中包含:結(jié)構(gòu)、樣式、功能

結(jié)構(gòu):基于template構(gòu)建        

+ 只能有一個根元素節(jié)點(vue2)
     + vue的視圖就是基于template語法構(gòu)建的(各種指令&小胡子...),最后vue會把其編譯為真實的DOM插入到頁面指定的容器中
      首先基于 vue-template-compiler 插件把template語法編譯為虛擬DOM「vnode」
      其次把本次編譯出來的vnode和上一次的進行對比,計算出差異化的部分「DOM-DIFF」
      最后把差異化的部分變?yōu)檎鎸嵉腄OM放在頁面中渲染
 

樣式:基于style來處理

  • + lang="less" 指定使用的CSS預編譯語言「需要提前安裝對應(yīng)的loader」

  • + scoped 指定當前編寫的樣式是私有的,只對當前組件中的結(jié)構(gòu)生效,后期組件合并在一起,保證樣式之間不沖突

功能:通過script處理

   + 導出的這個對象是VueComponent類的實例(也是Vue的實例):對象 -> VueComponent.prototype -> Vue.prototype
    + 在對象中基于各種 options api 「例如:data、methods、computed、watch、filters、生命周期函數(shù)...」實現(xiàn)當前組件的功能
       + 在組件中的data不再是一個對象,而是一個“閉包”
       + 各個組件最后會合并在一起渲染,為了保證組件中指定的響應(yīng)式數(shù)據(jù)是“私有的”,組件之間數(shù)據(jù)即使名字相同,也不會相互污染...所以需要基于閉包來管理

注意;App.vue頁面入口相當于首頁,寫好的組件都導入到這個里面

<template>
  <p class="box">
    {{ msg }}
  </p>
</template>

<script>
export default {
  name: "Test",
  data() {
    return {
      //編寫響應(yīng)式數(shù)據(jù)
      msg: "你好,世界",
    };
  },
};
</script>

<style lang="less" scoped>
.box {
  font-size: 20px;
  color: red;
}
</style>

私有組件(使用的時候首先進行導入,然后注冊,這樣視圖中就可以調(diào)用組件進行渲染了)

  • 需要使用私有組件的時候,需要先導入import Test from "./Test.vue";

  • 然后注冊:這樣就可以調(diào)用組件進行渲染了

<template>
  <p id="app">
      //3.使用組件:可以使用單閉合或雙閉合
      
    <Test></Test>
      <Test>
  </p>
</template>


<script>
//1、導入組件
import Test from "./Test.vue";
export default {
  name: "App",
  components:{
    //2、注冊使用的組件
    Test,
  }
};
</script>

創(chuàng)建全局組件

1. 創(chuàng)建一個局部組件

<template>
  <p>{{ msg }}</p>
</template>

<script>
export default {
  name: "Vote",
  data() {
    return {
      msg: "今夜陽光明媚",
    };
  },
};
</script>

@2 在main.js入口中,導入局部組件Vote,把其注冊為全局組件

import Vote from './Vote.vue';
Vue.component('Vote', Vote)

@3 這樣在任何組件(視圖中),無需基于components注冊,直接可以在視圖中調(diào)用

<template> <Vote></Vote></template>

插槽

調(diào)用組件的方式

調(diào)用組件的時候,可以使用:

雙閉合 <Test></Test>

雙閉合的方式可以使用插槽slot

@1 在封裝的組件中,基于 <slot> 標簽預留位置
 @2 調(diào)用組件的時候,基于雙閉合的方式,把要插入到插槽中的內(nèi)容寫在雙閉合之間

單閉合 <Test/>

組件的名字可以在“kebab-case”和“CamelCase”來切換:官方建議組件名字基于CamelCase命名,渲染的時候基于kebab-case模式使用!

VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析

插槽的作用

  • 讓組件具備更高的復用性(或擴展性)

  • 我們封裝好一個組件,把核心部分都實現(xiàn)了,但是我們期望用戶調(diào)用組件的時候,可以自定義一些內(nèi)容,防止在已經(jīng)封裝好的組件內(nèi)部:

插槽分為了默認插槽、具名插槽、作用域插槽,

默認插槽:只需要在調(diào)用組件<Test><Test>內(nèi)插入我們想要的插入的html代碼,會默認放到組件源代碼的<slot name="default"></slot>插槽中

組件內(nèi)部
slot預留位置  默認name:default
<slot></slot>
調(diào)用組件的時候
//只有一個的時候可以不用template包裹
<Test>
<p class="top">頭部導航</p>
</Test>

具名插槽:組件中預設(shè)好多插槽位置,為了后期可以區(qū)分插入到哪,我們把插槽設(shè)置名字

  • 在調(diào)用組件<Test><Test>內(nèi)自己寫的代碼,我們用template包裹代碼,并把v-slot:xxx寫在template上,這時就會將xxx里面的代碼,包裹到組件源代碼的<slot name=”xxx“></slot>的標簽中

  • ==組件內(nèi)部:== <slot name="xxx"> 默認名字是default

  • ==調(diào)用組件:==需要把v-slot寫在template上

  組件內(nèi)部
      <slot name="xxx">
      默認名字是default
    調(diào)用組件:需要把v-slot寫在template上
      <template v-slot:xxx>
         ...
      </template>
      <template>
         ...
      </template>
    v-slot可以簡寫為#:#xxx

VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析

  作用域插槽:把組件內(nèi)部定義的數(shù)據(jù),拿到調(diào)用組件時候的視圖中使用

組件中data內(nèi)的數(shù)據(jù)只能在本模塊中使用,如果想讓調(diào)用組件的插槽也能獲取數(shù)據(jù),就需要對組件內(nèi)對的slot做bind綁定數(shù)據(jù),調(diào)用組件的template標簽做#top="AAA",獲取數(shù)

   ==組件內(nèi)部==:
 <slot name="top" :list="list" :msg="msg"></slot>
  • 把組件中的list賦值給list屬性,把msg賦值給msg屬性,插槽中提供了兩個作用域?qū)傩裕簂ist/msg

==調(diào)用組件==:
 <template #top="AAA"></template>
  • 定義一個叫做AAA的變量,來接收插槽中綁定的所有數(shù)據(jù)(對象格式)

  • 如果插槽名是default則使用v-slot="AAA":default="AAA"獲取數(shù)據(jù)

 組件內(nèi)部
      <slot name="top" :list="list" :msg="msg"></slot>
      把組件中的list賦值給list屬性,把msg賦值給msg屬性,插槽中提供了兩個作用域?qū)傩裕簂ist/msg

    調(diào)用組件
      <template #top="AAA"></template>
      定義一個叫做AAA的變量,來接收插槽中綁定的數(shù)據(jù)
      AAA={
        list:[...],
        msg:...
      }

VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析

組件傳參

調(diào)用組件的時候

每創(chuàng)建一個組件其實相當于創(chuàng)建一個自定義類,而調(diào)用這個組件就是創(chuàng)建VueCommponent(或者Vue)類的實例

  • 實例(this)->VueComponent.prototype->Vue.prototype->Object.prototype

  • 當前實例可以訪問Vue.prototype上的一些公共屬性和方法

組件中的script中存在的狀態(tài)值和屬性值?

  • ==狀態(tài)值==:data中的數(shù)據(jù)值稱為狀態(tài)值

  • ==屬性值==:props中的數(shù)據(jù)值稱為屬性值

  • 狀態(tài)值和屬性值是直接掛載到_vode對象的私有屬性中(所以狀態(tài)值和屬性值名字不能重復)

  • 我們在視圖template標簽中調(diào)用狀態(tài)值和屬性值,不需要加this,直接調(diào)用狀態(tài)名或?qū)傩悦?/strong>

  • 我們在功能script標簽中調(diào)用狀態(tài)值和屬性值,需要加this調(diào)用

  • ==computed(計算屬性)==:也是掛載實例上的,所以他們?nèi)齻€都不能重名

vue中的單向數(shù)據(jù)流

父子組件傳遞數(shù)據(jù)時,只能由父組件流向子組件,不能由子組件流向父組件。這樣會防止從子組件意外改變父級組件的狀態(tài),從而導致你的應(yīng)用的數(shù)據(jù)流向難以理解。

組件傳參的分類7種:

  • 父組件向子組件傳參:props

  • 子組件向父組件傳參:發(fā)布訂閱(@xxx給子組件標簽自定義事件、$emit)

  • 組件相互傳參(兄弟):發(fā)布訂閱(on、emit)【2和3傳參是一種】

  • 祖先向后代傳參(provide[提供],inject[接收])

  • vue實例屬性傳參(parent、children[n]、root、refs)

  • vuex

  • localStorage sessionStorage

1.父組件向子組件傳參

父組件向子組件傳參:props

  • 我們傳給組件的值,默認是==字符串類型==的,比如msg

  • 如果想傳==數(shù)字類型==的,則需要調(diào)用v-bind或冒號的形式傳值

  • 我們每調(diào)用一次coma,都會生成一個獨立的VueComponent的實例

第一步:父組件在組件調(diào)用標簽中自定義屬性

//如果想把data中的狀態(tài)值傳遞過去需要v-bind綁定
<coma msg="hello" :num="num"></coma>

注意 如果想把data中的狀態(tài)值傳遞過去需要v-bind綁定

第二步:子組件通過props接收(數(shù)組,對象)

  • props中的屬性是只讀的,子組件不能修改這些值,否則會報錯

  • 解決只讀問題:用自定義變量接收傳遞過來的值,頁面使用自定義變量

  • props可以是對象或數(shù)組類型,對象可以對數(shù)據(jù)做校驗,數(shù)組不能

    // props的值是只讀的 能改,會報錯
    <input type="text" v-model="num" />
    //數(shù)組格式
    props:["msg","num"]
    //對象格式
     props: {
    msg: {
      //傳參類型必須是字符串
      type: String,
      //必須傳參
      required: true,
    },
    num: {
      type: Number,
      //如果不傳參默認是102
      default: 102,
    },
  },
    //----------------------------------------
    //用自定義變量numa接收num,然后頁面使用numa(解決只讀問題)
    <h2>我是子組件 coma------{{ msg }}----{{ numa }}</h2>
    <input type="text" v-model="numa" />
    props: ["msg", "num"],
      data() {
        return {
        numa: this.num,
       };
     },

2.子組件向父組件傳參

子組件向父組件傳參,基于==發(fā)布訂閱(@xxx給子組件標簽自定義事件、$emit)==

第一步:父組件在調(diào)用子組件的標簽上需要自定義一個事件,這個事件及綁定的方法就會添加到子組件的事件池中:底層實質(zhì)上是調(diào)用了this.$on("myEvent",fn)

<Coma @myEvent="getData"></Coma>
 methods: {
    getData() {},
  },

第二步:子組件用this.$emit()接受(this.$emit(myEvent,參數(shù)1,參數(shù)2)), 參數(shù)可以是子組件的,順便傳給父組件,實現(xiàn)子組件向父組件傳值

  <button @click="goParentData">向父組件發(fā)送數(shù)據(jù)</button>
 data() {
    return {
      flag: "你很美",
      n: 101,
    };
  methods: {
    goParentData() {
      //執(zhí)行父組件自定義的事件
      this.$emit("myEvent", this.flag, this.n);
    },
  },

第三步:父組件使用傳遞過來的數(shù)據(jù)

 data() {
    return {
      n: 0,
      flag: "",
    };
  },
  methods: {
    getData(...parans) {
      console.log(parans);
      //傳遞過來的是數(shù)組
      this.n = parans[0];
      this.flag = parans[1];
    },
  },

3.組件之間相互傳參    原生事件法  (發(fā)布訂閱)

b--->c發(fā)送數(shù)據(jù)

  • c向事件池中添加方法(自定義方法):$on

  • b執(zhí)行方法把參數(shù)傳過去:$emit

第一步:全局的main.js中創(chuàng)建一個全局的EventBus,掛載 vue的原型上  this.$bus

  • 作用:將EventBus看作定義在公有屬性上的事件池(事件公交),之后基于這個$bus.$on()綁定的事件函數(shù),在哪個vue實例上都可以基于$bus.$empty()執(zhí)行,還可以傳值

//創(chuàng)建一個全局的 Eventbus
let Eventbus=new Vue();
//掛載 vue的原型上  后期基于this.$bus
Vue.prototype.$bus=Eventbus;

第二步:comc向事件池中綁定事件:this.$bus.$on("事件名",函數(shù))

  created() {
    //向事件池中添加方法
    this.$bus.$on("myEvent", () => {});
  },

第三步:comb從事件池中獲取事件函數(shù)并執(zhí)行:this.$bus.$emit("事件名",想傳的參數(shù))

    <button @click="send">發(fā)送數(shù)據(jù)給comc</button>
      data() {
        return {
          msg: "我是comb",
    };
    methods: {
    send() {
      //執(zhí)行事件池中的方法,并且傳參
      this.$bus.$emit("myEvent", this.msg);
    },

第四步 comc使用傳遞過來的數(shù)據(jù)

   <h2>組件 comc----{{ msg }}</h2>
     data() {
        return {
          msg: "",
      };
  //創(chuàng)建之后的鉤子函數(shù)向事件池中添加方法
 created() {
    //向事件池中添加方法
    this.$bus.$on("myEvent", (value) => {
      console.log(value);
      this.msg = value;
    });
  },

4.祖先和后代相互傳參

  • 第一步:祖先要使用provide方法傳參,不是寫在methods里面,與methods同級

 data() {
    return {
      title: "我是about祖先",
    };
  },
  provide() {
    return {
      title: this.title,
    };
  },

第二步:后代使用inject屬性接受祖先中的參數(shù),inject是data中的數(shù)據(jù),是數(shù)組類型

inject: ["title"],因為inject是數(shù)組類型,所以它符合如果數(shù)據(jù)項不是對象類型,則不做劫持,如果數(shù)據(jù)項是對象,則這個對象中的屬性會做劫持。

  data() {
    return {
      title: "我是about祖先",
    };
  },
//祖先 傳遞的title是非響應(yīng)式
  provide() {
    return {
      title: this.title,
    };
  },
//------------------------------
  data() {
    return {
      //obj非響應(yīng)式
      obj: {
        //title是響應(yīng)式
        title: "我是about祖先",
      },
    };
  },
  //祖先 傳遞的參數(shù)失去響應(yīng)式,但里面的值會是響應(yīng)式
  provide() {
    return {
      obj: this.obj,
    };
  },

vue實例屬性傳參

vue的實例中存在一些屬性能夠獲取不同關(guān)系的元素,獲取之后就可以基于這個元素獲取其中的數(shù)據(jù)或方法了:

  • $parent 獲取父元素的數(shù)據(jù)/方法  獲取父元素的整個vm實例

  • 子組件可以在任何生命周期函數(shù)中獲取父元素【父子組件的生命周期

  created() {
    console.log(this.$parent.title);
  },
  • $children  獲取子元素的數(shù)據(jù)/方法(mounted鉤子函數(shù),要有下標)

  • this.$children[n]:獲取第n個子元素的vm實例

  • 父組件只能在mounted生命周期函數(shù)里或之后獲取子元素【父子組件的生命周期

  mounted() {
    console.log(this.$children[0].msg);
  },
  • $root獲取根組件的數(shù)據(jù)/方法

  • this.$root:獲取根元素的vm實例(main.js中new 的Vue實例)

et mv = new Vue({
  router,
  data() {
    return {
      rootmsg: "我是草根"
    }
  },
  render: h => h(App)
}).$mount('#app')
---------------------
  mounted() {
    console.log(this.$root.rootmsg);
  },
  • this.$refs:this的子元素中需要定義ref屬性:比如ref="xxx"

  • ==如果ref定義在DOM標簽中==:this.$refs.xxx獲取的是DOM對象

  • ==如果ref定義在子組件標簽中==:this.$refs.xxx獲取的是子組件的vm實例

  //獲取的是dom元素
  <p ref="one">11111</p>
   mounted() {
    console.log(this.$refs.one);
  },
-----------------------------------
獲取的是組件
  <comb ref="b"></comb>
  mounted() {
    console.log(this.$refs.b);
  },
//如果不是組件獲取的就是dom元素,如果是組件,獲取的就是組件的實例

父子組件的生命周期

重點:父組件更新默認不會觸發(fā)子組件更新,但是**==如果子組件中綁定調(diào)用了父組件的數(shù)據(jù)aaa,父組件的aaa數(shù)據(jù)更新觸發(fā)重新渲染時,使用aaa數(shù)據(jù){{$parent.aaa}}的子組件也會觸發(fā)更新==**

一、父子組件生命周期執(zhí)行過程

  • 父->beforeCreated

  • 父->created

  • 父->beforeMount

  • 子->beforeCreate

  • 子->created

  • 子->beforeMount

  • 子->mounted

  • 父->mounted

二、子組件更新過程:

  • 父->berforeUpdate

  • 子->berforeUpdate

  • 子->updated

  • 父->updated

三、父組件更新過程:

  • 父->berforeUpdate

  • 父->updated

四、父組件銷毀過程:

  • 父->beforeDestory

  • beforeDestory

  • destoryed

  • 父->destoryed

VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析

擴展------------------------

父組件綁定在子組件標簽中的事件,是無法觸發(fā)的,如何解決?

@xxx.native: 監(jiān)聽組件根元素的原生事件。

  • 例子<my-component @click.native="onClick"></my-component>

  • 原理:在父組件中給子組件綁定一個==原生(click/mouseover...)==的事件,就將子組件變成了普通的HTML標簽,不加'. native'父組件綁定給子組件標簽的事件是無法觸發(fā)的

虛擬DOM

虛擬DOM對象:_vnode,作用:

第一步:vue內(nèi)部自己定義的一套對象,基于自己規(guī)定的鍵值對,來描述視圖中每一個節(jié)點的特征:

  • tag標簽名

  • text文本節(jié)點,存儲文本內(nèi)容

  • children:子節(jié)點

  • data:屬性

  • 第二步:基于vue-template-compiler去渲染解析 template 視圖,最后構(gòu)建出上述的虛擬DOM對象

  • 第三步:組件重新渲染,又重新生成一個 _vnode

  • 第四步:對比兩次的 _vnode. 獲取差異的部分

  • 第五步:把差異的部分渲染為真實的DOM

組件庫

  • element-ui:餓了么

  • antdv :螞蟻金服

  • iview :京東

  • Element - The world's most popular Vue UI framework

  • ==vue2.xx==:elemnetui

  • ==vue3.xx==:element plus

如何在項目中使用功能性組件?

==第一步==:安裝element-ui:$npm i element-ui -s

==第二步==:導入:

完整導入:整個組件庫都導入進來,想用什么直接用Vue.use(xxx)即可

缺點:如果我們只用幾個組件,則無用的導入組件會造成項目打包體積變大[不好],所以項目中推薦使用按需導入

按需導入

1、需要安裝依賴$ npm install babel-plugin-component

樣式私有化

在Vue中我們基于scoped設(shè)置樣式私有化之后:

  • 會給組件創(chuàng)建一個唯一的ID(例如:data-v-5f109989)

  • 在組件視圖中,我們編寫所有元素(包含元素調(diào)用的UI組件),都設(shè)置了這個ID屬性;但是我們調(diào)用的組件內(nèi)部的元素,并沒有設(shè)置這個屬性??!

   <p data-v-5f1969a9 class="task-box">
      <button data-v-5f1969a9 type="button" class="el-button el-button--primary">
        <span>新增任務(wù)</span>
      </button>
    </p>

而我們編寫的樣式,最后會自動加上屬性選擇器:

 .task-box {
      box-sizing: border-box;
      ...
    }
---------編譯后成為:---------
    .task-box[data-v-5f1969a9]{
      box-sizing: border-box;
    }
  • ==組件樣式私有化的原理==:設(shè)置唯一的屬性(組件ID)、組件內(nèi)部給所有樣式后面都加上該屬性選擇器

  • ==問題==:組件內(nèi)部的元素沒有設(shè)置這個屬性,但是我們編寫的樣式是基于這個屬性選擇器在css設(shè)置的選擇器,

  • ==解決==:在組件內(nèi)部的元素選擇器前加/deep/:

    /deep/.el-textarea__inner,
    	/deep/.el-input__inner{
   		 border-radius: 0;
 		 }

API

  • 在真實項目中,我們會把數(shù)據(jù)請求和axios的二次封裝,都會放到src/api路徑下進行管理

//main.js
	import api from '@/api/index';
	// 把存儲接口請求的api對象掛載搭配Vue的原型上:
    后續(xù)在各個組件基于this.$api.xxx()就可以發(fā)送請求了,無需在每個組件中再單獨導入這個api對象。
	Vue.prototype.$api=api;

以上就是關(guān)于“VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI