VUE兩大核心之響應式與元件化開發詳解

2022-08-08 18:01:25
本篇文章給大家帶來了關於的相關知識,其中主要介紹了關於vue的兩大核心,響應式與元件化的相關問題,下面一起來看一下,希望對大家有幫助。

【相關推薦:、】

vue2.0 響應式

1. 物件的響應式

1.1 Object.defineProperty

Object.defineProperty(obj, prop, descriptor)方法會直接在一個物件上定義一個新屬性,或者修改一個物件的現有屬性,並返回此物件。

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

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

通過賦值操作新增的普通屬性是可列舉的,在列舉物件屬性時會被列舉到(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響應式過程const app = document.getElementById('app')const data = {
	a: {
	  b: {
	    c: 1
	  }
	}}function render () {
  const virtualDom = `這是我的內容${data.a.b.c}`		
  app.innerHTML = virtualDom}function observer (obj) {
  let value  for (const key in obj) {  // 遞迴設定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)

上述方法實現了資料的響應,但存在很大的問題,我們觸發一次set,就需要整個頁面重新渲染,然而這個值可能只在某一個元件中使用了。
在這裡插入圖片描述

所以將get和set優化:

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 執行 getter/setter 轉化,所以 property 必須在 data 物件上存在才能讓 Vue 將它轉換為響應式的

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

2. 陣列的響應式

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

Object.create(proto,[propertiesObject]) 方法是建立一個新物件,使用現有的物件來提供新建立的物件的__proto__

proto——新建立物件的原型物件;
propertiesObject ——選填,型別是物件,如果該引數被指定且不為 undefined,該傳入物件的自有可列舉屬性(即其自身定義的屬性,而不是其原型鏈上的列舉屬性)將為新建立的物件新增指定的屬性值和對應的屬性描述符

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會成為所建立物件的資料屬性
    writable:true,
    configurable:true,
    value: "hello"
  },
  bar: { // bar會成為所建立物件的存取器屬性
    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的原型建立一個新物件,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) // 重寫時先呼叫原生方法
    dep.notify() // 並且同時更新
  }})// 對於使用者定義的陣列,手動將陣列的__proto__指向我們修改過的原型const a = [1, 2, 3]a.__proto__ = arrob

上面對於新物件arrob的方法,我們是直接賦值的,這樣會有一個問題,就是使用者可能會不小心改掉我們的物件,所以我們可以用到我們前面講到的Object.defineProperty來規避這個問題,我們建立一個公用方法def專門來設定不能修改值的屬性

function def (obj, key, value) {
  Object.defineProperty(obj, key, {
    // 這裡我們沒有指定writeable,預設為false,即不可修改
    enumerable: true,
    configurable: true,
    value: value,
  });}// 陣列方法重寫改為arr.forEach(function(method){
  def(arrob, method, function () {
    arraypro[method].apply(this, arguments)  // 重寫時先呼叫原生方法
    dep.notify()// 並且同時更新
  })})

3. 補充:物件的資料屬性和存取器屬性

資料屬性: 它包含的是一個資料值的位置,在這可以對資料值進行讀寫

資料屬性的四個描述符:


含義
configurable表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或能否把屬性修改為存取器屬性,預設為true
enumerable表示能否通過for-in迴圈返回屬性,預設為true
writable表示能否修改屬性的值,預設為true
value包含該屬性的資料值,預設為undefined

存取器屬性: 這個屬性不包含資料值,包含的是一對get和set方法,在讀寫存取器屬性時,就是通過這兩個方法來進行操作處理的。

存取器屬性的四個描述符:


含義
configurable表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或能否把屬性修改為存取器屬性,預設為false
enumerable表示能否通過for-in迴圈返回屬性,預設為false
get在讀取屬性時呼叫的函數,預設值為undefined
set在寫入屬性時呼叫的函數,預設值為undefined

vue3.0資料響應

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

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

  1. Object.defineProperty需要指定物件和屬性,對於多層巢狀的物件需要遞迴監聽,Proxy可以直接監聽整個物件,不需要遞迴;
  2. Object.defineProperty的get方法沒有傳入引數,如果我們需要返回原值,需要在外部快取一遍之前的值,Proxy的get方法會傳入物件和屬性,可以直接在函數內部操作,不需要外部變數;
  3. set方法也有類似的問題,Object.defineProperty的set方法傳入引數只有newValue,也需要手動將newValue賦給外部變數,Proxy的set也會傳入物件和屬性,可以直接在函數內部操作;
  4. new Proxy()會返回一個新物件,不會汙染源原物件
  5. Proxy可以監聽陣列,不用單獨處理陣列

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

這樣上邊的observe方法就可以優化成:

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
    }
  });}

模組化(元件化)開發

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

目的 :方便團隊共同作業開發 實現複用

元件分類

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

  • + 一般UI元件庫提供的功能元件就夠用了
  • + 偶爾UI元件庫中不存在的,才需要自己封裝「難點」
  • + 我們經常會把功能型元件進行二次封裝(結合自己專案的業務邏輯)「特殊亮點」

業務型元件

  • + 通用業務型元件「好多頁面都需要用到的,我們把其封裝成為公共的元件」
  • + 普通元件

以後開發專案,拿到設計稿的第一件事情:劃分元件「按照功能版塊劃分、本著複用性原則,拆的越細越好(這樣才能更好的實現複用)」

元件的建立及使用

建立一個 Xxx.vue 就是建立一個vue元件{區域性元件、私有元件},元件中包含:結構、樣式、功能

結構:基於template構建

+ 只能有一個根元素節點(vue2)
+ vue的檢視就是基於template語法構建的(各種指令&小鬍子...),最後vue會把其編譯為真實的DOM插入到頁面指定的容器中
首先基於 vue-template-compiler 外掛把template語法編譯為虛擬DOM「vnode」
其次把本次編譯出來的vnode和上一次的進行對比,計算出差異化的部分「DOM-DIFF」
最後把差異化的部分變為真實的DOM放在頁面中渲染

樣式:基於style來處理

  • + lang="less" 指定使用的CSS預編譯語言「需要提前安裝對應的loader」
  • + scoped 指定當前編寫的樣式是私有的,只對當前元件中的結構生效,後期元件合併在一起,保證樣式之間不衝突

功能:通過script處理

+ 匯出的這個物件是VueComponent類的範例(也是Vue的範例):物件 -> VueComponent.prototype -> Vue.prototype
+ 在物件中基於各種 options api 「例如:data、methods、computed、watch、filters、生命週期函數...」實現當前元件的功能
+ 在元件中的data不再是一個物件,而是一個「閉包」
+ 各個元件最後會合並在一起渲染,為了保證元件中指定的響應式資料是「私有的」,元件之間資料即使名字相同,也不會相互汙染...所以需要基於閉包來管理

注意;App.vue頁面入口相當於首頁,寫好的元件都匯入到這個裡面

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

<script>
export default {
  name: "Test",
  data() {
    return {
      //編寫響應式資料
      msg: "你好,世界",
    };
  },
};
</script>

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

私有元件(使用的時候首先進行匯入,然後註冊,這樣檢視中就可以呼叫元件進行渲染了)

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

  • 然後註冊:這樣就可以呼叫元件進行渲染了

<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>

建立全域性元件

1. 建立一個區域性元件

<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註冊,直接可以在檢視中呼叫

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

插槽

呼叫元件的方式

呼叫元件的時候,可以使用:

雙閉合 <Test></Test>

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

@1 在封裝的元件中,基於 <slot> 標籤預留位置
@2 呼叫元件的時候,基於雙閉合的方式,把要插入到插槽中的內容寫在雙閉合之間

單閉合 <Test/>

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

插槽的作用

  • 讓元件具備更高的複用性(或擴充套件性)
  • 我們封裝好一個元件,把核心部分都實現了,但是我們期望使用者呼叫元件的時候,可以自定義一些內容,防止在已經封裝好的元件內部:

插槽分為了預設插槽、具名插槽、作用域插槽

預設插槽:只需要在呼叫元件<Test><Test>內插入我們想要的插入的html程式碼,會預設放到元件原始碼的<slot name="default"></slot>插槽中

元件內部
slot預留位置  預設name:default
<slot></slot>
呼叫元件的時候
//只有一個的時候可以不用template包裹
<Test>
<p class="top">頭部導航</p>
</Test>

具名插槽:元件中預設好多插槽位置,為了後期可以區分插入到哪,我們把插槽設定名字

  • 在呼叫元件<Test><Test>內自己寫的程式碼,我們用template包裹程式碼,並把v-slot:xxx寫在template上,這時就會將xxx裡面的程式碼,包裹到元件原始碼的<slot name=」xxx「></slot>的標籤中
  • ==元件內部:== <slot name="xxx"> 預設名字是default
  • ==呼叫元件:==需要把v-slot寫在template上
  元件內部
      <slot name="xxx">
      預設名字是default
    呼叫元件:需要把v-slot寫在template上
      <template v-slot:xxx>
         ...
      </template>
      <template>
         ...
      </template>
    v-slot可以簡寫為#:#xxx

作用域插槽:把元件內部定義的資料,拿到呼叫元件時候的檢視中使用

元件中data內的資料只能在本模組中使用,如果想讓呼叫元件的插槽也能獲取資料,就需要對元件內對的slot做bind繫結資料,呼叫元件的template標籤做#top="AAA",獲取數

   ==元件內部==:
 <slot name="top" :list="list" :msg="msg"></slot>
  • 把元件中的list賦值給list屬性,把msg賦值給msg屬性,插槽中提供了兩個作用域屬性:list/msg
==呼叫元件==:
 <template #top="AAA"></template>
  • 定義一個叫做AAA的變數,來接收插槽中繫結的所有資料(物件格式)
  • 如果插槽名是default則使用v-slot="AAA":default="AAA"獲取資料
 元件內部
      <slot name="top" :list="list" :msg="msg"></slot>
      把元件中的list賦值給list屬性,把msg賦值給msg屬性,插槽中提供了兩個作用域屬性:list/msg

    呼叫元件
      <template #top="AAA"></template>
      定義一個叫做AAA的變數,來接收插槽中繫結的資料
      AAA={
        list:[...],
        msg:...
      }

元件傳參

呼叫元件的時候

每建立一個元件其實相當於建立一個自定義類,而呼叫這個元件就是建立VueCommponent(或者Vue)類的範例

  • 範例(this)->VueComponent.prototype->Vue.prototype->Object.prototype
  • 當前範例可以存取Vue.prototype上的一些公共屬性和方法

元件中的script中存在的狀態值和屬性值?

  • ==狀態值==:data中的資料值稱為狀態值
  • ==屬性值==:props中的資料值稱為屬性值
  • 狀態值和屬性值是直接掛載到_vode物件的私有屬性中(所以狀態值和屬性值名字不能重複)
  • 我們在檢視template標籤中呼叫狀態值和屬性值,不需要加this,直接呼叫狀態名或屬性名
  • 我們在功能script標籤中呼叫狀態值和屬性值,需要加this呼叫
  • ==computed(計算屬性)==:也是掛載範例上的,所以他們三個都不能重名

vue中的單向資料流

父子元件傳遞資料時,只能由父元件流向子元件,不能由子元件流向父元件。這樣會防止從子元件意外改變父級元件的狀態,從而導致你的應用的資料流向難以理解。

元件傳參的分類7種:

  • 父元件向子元件傳參:props
  • 子元件向父元件傳參:釋出訂閱(@xxx給子元件標籤自定義事件、$emit)
  • 元件相互傳參(兄弟):釋出訂閱(on、emit)【2和3傳參是一種】
  • 祖先向後代傳參(provide[提供],inject[接收])
  • vue範例屬性傳參(parent、children[n]、root、refs)
  • vuex
  • localStorage sessionStorage

1.父元件向子元件傳參

父元件向子元件傳參:props

  • 我們傳給元件的值,預設是==字串型別==的,比如msg
  • 如果想傳==數位型別==的,則需要呼叫v-bind或冒號的形式傳值
  • 我們每呼叫一次coma,都會生成一個獨立的VueComponent的範例

第一步:父元件在元件呼叫標籤中自定義屬性

//如果想把data中的狀態值傳遞過去需要v-bind繫結
<coma msg="hello" :num="num"></coma>

注意 如果想把data中的狀態值傳遞過去需要v-bind繫結

第二步:子元件通過props接收(陣列,物件)

  • props中的屬性是唯讀的,子元件不能修改這些值,否則會報錯
  • 解決唯讀問題:用自定義變數接收傳遞過來的值,頁面使用自定義變數
  • props可以是物件或陣列型別,物件可以對資料做校驗,陣列不能
    // props的值是唯讀的 能改,會報錯
    <input type="text" v-model="num" />
    //陣列格式
    props:["msg","num"]
    //物件格式
     props: {
    msg: {
      //傳參型別必須是字串
      type: String,
      //必須傳參
      required: true,
    },
    num: {
      type: Number,
      //如果不傳參預設是102
      default: 102,
    },
  },
    //----------------------------------------
    //用自定義變數numa接收num,然後頁面使用numa(解決唯讀問題)
    <h1>我是子元件 coma------{{ msg }}----{{ numa }}</h1>
    <input type="text" v-model="numa" />
    props: ["msg", "num"],
      data() {
        return {
        numa: this.num,
       };
     },

2.子元件向父元件傳參

子元件向父元件傳參,基於==釋出訂閱(@xxx給子元件標籤自定義事件、$emit)==

第一步:父元件在呼叫子元件的標籤上需要自定義一個事件,這個事件及繫結的方法就會新增到子元件的事件池中:底層實質上是呼叫了this.$on("myEvent",fn)

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

第二步:子元件用this.$emit()接受(this.$emit(myEvent,引數1,引數2)), 引數可以是子元件的,順便傳給父元件,實現子元件向父元件傳值

  <button @click="goParentData">向父元件傳送資料</button>
 data() {
    return {
      flag: "你很美",
      n: 101,
    };
  methods: {
    goParentData() {
      //執行父元件自定義的事件
      this.$emit("myEvent", this.flag, this.n);
    },
  },

第三步:父元件使用傳遞過來的資料

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

3.元件之間相互傳參 原生事件法 (釋出訂閱)

b--->c傳送資料

  • c向事件池中新增方法(自定義方法):$on
  • b執行方法把引數傳過去:$emit

第一步:全域性的main.js中建立一個全域性的EventBus,掛載 vue的原型上 this.$bus

  • 作用:將EventBus看作定義在公有屬性上的事件池(事件公交),之後基於這個$bus.$on()繫結的事件函數,在哪個vue範例上都可以基於$bus.$empty()執行,還可以傳值
//建立一個全域性的 Eventbus
let Eventbus=new Vue();
//掛載 vue的原型上  後期基於this.$bus
Vue.prototype.$bus=Eventbus;

第二步:comc向事件池中繫結事件:this.$bus.$on("事件名",函數)

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

第三步:comb從事件池中獲取事件函數並執行:this.$bus.$emit("事件名",想傳的引數)

    <button @click="send">傳送資料給comc</button>
      data() {
        return {
          msg: "我是comb",
    };
    methods: {
    send() {
      //執行事件池中的方法,並且傳參
      this.$bus.$emit("myEvent", this.msg);
    },

第四步 comc使用傳遞過來的資料

   <h1>元件 comc----{{ msg }}</h1>
     data() {
        return {
          msg: "",
      };
  //建立之後的勾點函數向事件池中新增方法
 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屬性接受祖先中的引數,inject是data中的資料,是陣列型別

inject: ["title"],因為inject是陣列型別,所以它符合如果資料項不是物件型別,則不做劫持,如果資料項是物件,則這個物件中的屬性會做劫持。

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

vue範例屬性傳參

vue的範例中存在一些屬效能夠獲取不同關係的元素,獲取之後就可以基於這個元素獲取其中的資料或方法了:

  • $parent 獲取父元素的資料/方法 獲取父元素的整個vm範例
  • 子元件可以在任何生命週期函數中獲取父元素【父子元件的生命週期
  created() {
    console.log(this.$parent.title);
  },
  • $children 獲取子元素的資料/方法(mounted勾點函數,要有下標)
  • this.$children[n]:獲取第n個子元素的vm範例
  • 父元件只能在mounted生命週期函數裡或之後獲取子元素【父子元件的生命週期
  mounted() {
    console.log(this.$children[0].msg);
  },
  • $root獲取根元件的資料/方法
  • 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元素,如果是元件,獲取的就是元件的範例

父子元件的生命週期

重點:父元件更新預設不會觸發子元件更新,但是**==如果子元件中繫結呼叫了父元件的資料aaa,父元件的aaa資料更新觸發重新渲染時,使用aaa資料{{$parent.aaa}}的子元件也會觸發更新==**

一、父子元件生命週期執行過程

  • 父->beforeCreated
  • 父->created
  • 父->beforeMount
  • 子->beforeCreate
  • 子->created
  • 子->beforeMount
  • 子->mounted
  • 父->mounted

二、子元件更新過程:

  • 父->berforeUpdate
  • 子->berforeUpdate
  • 子->updated
  • 父->updated

三、父元件更新過程:

  • 父->berforeUpdate
  • 父->updated

四、父元件銷燬過程:

  • 父->beforeDestory
  • beforeDestory
  • destoryed
  • 父->destoryed

擴充套件------------------------

父元件繫結在子元件標籤中的事件,是無法觸發的,如何解決?

@xxx.native: 監聽元件根元素的原生事件。

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

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

虛擬DOM

虛擬DOM物件:_vnode,作用:

第一步:vue內部自己定義的一套物件,基於自己規定的鍵值對,來描述檢視中每一個節點的特徵:

  • tag標籤名
  • text文位元組點,儲存文字內容
  • children:子節點
  • data:屬性
  • 第二步:基於vue-template-compiler去渲染解析 template 檢視,最後構建出上述的虛擬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設定樣式私有化之後:

  • 會給元件建立一個唯一的ID(例如:data-v-5f109989)

  • 在元件檢視中,我們編寫所有元素(包含元素呼叫的UI元件),都設定了這個ID屬性;但是我們呼叫的元件內部的元素,並沒有設定這個屬性!!

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

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

 .task-box {
      box-sizing: border-box;
      ...
    }
---------編譯後成為:---------
    .task-box[data-v-5f1969a9]{
      box-sizing: border-box;
    }
  • ==元件樣式私有化的原理==:設定唯一的屬性(元件ID)、元件內部給所有樣式後面都加上該屬性選擇器
  • ==問題==:元件內部的元素沒有設定這個屬性,但是我們編寫的樣式是基於這個屬性選擇器在css設定的選擇器,
  • ==解決==:在元件內部的元素選擇器前加/deep/:
    /deep/.el-textarea__inner,
    	/deep/.el-input__inner{
   		 border-radius: 0;
 		 }

API

  • 在真實專案中,我們會把資料請求和axios的二次封裝,都會放到src/api路徑下進行管理

//main.js
	import api from '@/api/index';
	// 把儲存介面請求的api物件掛載搭配Vue的原型上:
    後續在各個元件基於this.$api.xxx()就可以傳送請求了,無需在每個元件中再單獨匯入這個api物件。
	Vue.prototype.$api=api;

【相關推薦:、】

以上就是VUE兩大核心之響應式與元件化開發詳解的詳細內容,更多請關注TW511.COM其它相關文章!