您好,登錄后才能下訂單哦!
這篇“VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“VUE兩大核心之響應(yīng)式與組件化開發(fā)實例分析”文章吧。
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
// 模擬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,就需要整個頁面重新渲染,然而這個值可能只在某一個組件中使用了。
所以將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)式的
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()// 并且同時更新 })})
數(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的響應(yīng)式和vue2.0響應(yīng)式原理類似,都是在get中收集依賴,在set中通知依賴更新視圖,但vue3.0使用了es6新增的proxy來代替Object.defineProperty()
proxy相對于Object.defineProperty()的好處:
Object.defineProperty需要指定對象和屬性,對于多層嵌套的對象需要遞歸監(jiān)聽,Proxy可以直接監(jiān)聽整個對象,不需要遞歸;
Object.defineProperty的get方法沒有傳入?yún)?shù),如果我們需要返回原值,需要在外部緩存一遍之前的值,Proxy的get方法會傳入對象和屬性,可以直接在函數(shù)內(nèi)部操作,不需要外部變量;
set方法也有類似的問題,Object.defineProperty的set方法傳入?yún)?shù)只有newValue,也需要手動將newValue賦給外部變量,Proxy的set也會傳入對象和屬性,可以直接在函數(shù)內(nèi)部操作;
new Proxy()會返回一個新對象,不會污染源原對象
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 } });}
按照功能(或按照復用性)把一個頁面拆成各個板塊(模塊),每一個模塊都是一個單獨的文件(單獨的組件),最后把各個模塊(組件)拼在一起即可??!
目的 :方便團隊協(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模式使用!
插槽的作用
讓組件具備更高的復用性(或擴展性)
我們封裝好一個組件,把核心部分都實現(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
作用域插槽:把組件內(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:... }
調(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的實例中存在一些屬性能夠獲取不同關(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
@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; }
在真實項目中,我們會把數(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è)資訊頻道。
免責聲明:本站發(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)容。