免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      vue3源碼分析-實現(xiàn)props,emit,事件處理等

      引言

    1. vue3源碼分析——rollup打包monorepo
    2. vue3源碼分析——實現(xiàn)組件的掛載流程
    3. 本期來實現(xiàn),setup里面使用props,父子組件通信props和emit等,所有的源碼請查看

      本期的內(nèi)容與上一期的代碼具有聯(lián)動性,所以需要明白本期的內(nèi)容,最后是先看下上期的內(nèi)容哦!

      實現(xiàn)render中的this

      在render函數(shù)中,可以通過this,來訪問setup返回的內(nèi)容,還可以訪問this.$el等

      測試用例

      由于是測試dom,jest需要提前注入下面的內(nèi)容,讓document里面有app節(jié)點,下面測試用例類似在html中定義一個app節(jié)點哦

      let appElement: Element; beforeEach(() => { appElement = document.createElement(‘p’); appElement.id = ‘app’; document.body.appendChild(appElement); }); afterEach(() => { document.body.innerHTML = ”; })復制代碼

      功能的測試用例正式開始

      test(‘實現(xiàn)代理對象,通過this來訪問’, () => { let that; const app = createApp({ render() { // 在這里可以通過this來訪問 that = this; return h(‘p’, { class: ‘container’ }, this.name); }, setup() { return { name: ‘123’ } } }); const appDoc = document.querySelector(‘#app’) app.mount(appDoc); // 綁定值后的html expect(document.body.innerHTML).toBe(‘123’); const elDom = document.querySelector(‘#container’) // el就是當前組件的真實dom expect(that.$el).toBe(elDom); })復制代碼

      分析

      上面的測試用例

    4. setup返回是對象的時候,綁定到render的this上面
    5. $el則是獲取的是當前組件的真實dom
    6. 解決這兩個需求:

    7. 需要在render調(diào)用的時候,改變當前函數(shù)的this指向,但是需要思考的一個問題是:this是啥,它既要存在setup,也要存在el,咋們是不是可以用一個proxy來綁定呢?在哪里創(chuàng)建呢 可以在處理組件狀態(tài)setupStatefulComponent來完成改操作
    8. el則是在mountElement中掛載真實dom的時候,把當前的真實dom綁定在vnode當中
    9. 編碼

      針對上面的分析,需要在setupStatefulComponent中來創(chuàng)建proxy并且綁定到instance當中,并且setup的執(zhí)行結(jié)果如果是對象,也已經(jīng)存在instance中了,可以通過instance.setupState來進行獲取

      function setupStatefulComponent(instance: any) { instance.proxy = new Proxy({}, { get(target, key){ // 判斷當前的key是否存在于instance.setupState當中 if(key in instance.setupState){ return instance.setupState[key] } } }) // …省略其他}// 然后在setupRenderEffect調(diào)用render的時候,改變當前的this執(zhí)行,執(zhí)行為instance.proxyfunction setupRenderEffect(instance: any, vnode: any, container: any) { // 獲取到vnode的子組件,傳入proxy進去 const { proxy } = instance const subtree = instance.render.call(proxy) // …省略其他}復制代碼

      通過上面的操作,從render中this.xxx獲取setup返回對象的內(nèi)容就ok了,接下來處理el

      需要在mountElement中,創(chuàng)建節(jié)點的時候,在vnode中綁定下,el,并且在setupStatefulComponent 中的代理對象中判斷當前的key

      // 代理對象進行修改 instance.proxy = new Proxy({}, { get(target, key){ // 判斷當前的key是否存在于instance.setupState當中 if(key in instance.setupState){ return instance.setupState[key] }else if(key === ‘$el’){ return instance.vnode.el } } }) // mount中需要在vnode中綁定el function mountElement(vnode: any, container: any) { // 創(chuàng)建元素 const el = document.createElement(vnode.type) // 設(shè)置vnode的el vnode.el = el //…… 省略其他 }復制代碼

      看似沒有問題吧,但是實際上是有問題的,請仔細思考一下,mountElement是不是比setupStatefulComponent 后執(zhí)行,setupStatefulComponent執(zhí)行的時候,vnode.el不存在,后續(xù)mountelement的時候,vnode就會有值,那么上面的測試用例肯定是報錯的,$el為null

      解決這個問題的關(guān)鍵,mountElement的加載順序是 render -> patch -> mountElement,并且render函數(shù)返回的subtree是一個vnode,改vnode中上面是mount的時候,已經(jīng)賦值好了el,所以在patch后執(zhí)行下操作

      function setupRenderEffect(instance: any, vnode: any, container: any) { // 獲取到vnode的子組件,傳入proxy進去 const { proxy } = instance const subtree = instance.render.call(proxy) patch(subtree, container) // 賦值vnode.el,上面執(zhí)行render的時候,vnode.el是null vnode.el = subtree.el}復制代碼

      至此,上面的測試用例就能ok通過啦!

      實現(xiàn)on+Event注冊事件

      在vue中,可以使用onEvent來寫事件,那么這個功能是怎么實現(xiàn)的呢,咋們一起來看看

      測試用例

      test(‘測試on綁定事件’, () => { let count = 0 console.log = jest.fn() const app = createApp({ render() { return h(‘p’, { class: ‘container’, onClick() { console.log(‘click’) count++ }, onFocus() { count– console.log(1) } }, ‘123’); } }); const appDoc = document.querySelector(‘#app’) app.mount(appDoc); const container = document.querySelector(‘.container’) as HTMLElement; // 調(diào)用click事件 container.click(); expect(console.log).toHaveBeenCalledTimes(1) // 調(diào)用focus事件 container.focus(); expect(count).toBe(0) expect(console.log).toHaveBeenCalledTimes(2) })復制代碼

      分析

      在本功能的測試用例中,可以分析以下內(nèi)容:

    10. onEvent事件是在props中定義的
    11. 事件的格式必須是 on + Event的格式
    12. 解決問題:

      這個功能比較簡單,在處理prop中做個判斷, 屬性是否滿足 /^on[A-Z]/i這個格式,如果是這個格式,則進行事件注冊,但是vue3會做事件緩存,這個是怎么做到?

      緩存也好實現(xiàn),在傳入當前的el中增加一個屬性 el._vei || (el._vei = {}) 存在這里,則直接使用,不能存在則創(chuàng)建并且存入緩存

      編碼

      在mountElement中增加處理事件的邏輯 const { props } = vnode for (let key in props) { // 判斷key是否是on + 事件命,滿足條件需要注冊事件 const isOn = (p: string) => p.match(/^on[A-Z]/i) if (isOn(key)) { // 注冊事件 el.addEventListener(key.slice(2).toLowerCase(), props[key]) } // … 其他邏輯 el.setAttribute(key, props[key]) }復制代碼

      事件處理就ok啦

      父子組件通信——props

      父子組件通信,在vue中是非常常見的,這里主要實現(xiàn)props與emit

      測試用例

      test(‘測試組件傳遞props’, () => { let tempProps; console.warn = jest.fn() const Foo = { name: ‘Foo’, render() { // 2. 組件render里面可以直接使用props里面的值 return h(‘p’, { class: ‘foo’ }, this.count); }, setup(props) { // 1. 此處可以拿到props tempProps = props; // 3. readonly props props.count++ } } const app = createApp({ name: ‘App’, render() { return h(‘p’, { class: ‘container’, }, [ h(Foo, { count: 1 }), h(‘span’, { class: ‘span’ }, ‘123’) ]); } }); const appDoc = document.querySelector(‘#app’) app.mount(appDoc); // 驗證功能1 expect(tempProps.count).toBe(1) // 驗證功能3,修改setup內(nèi)部的props需要報錯 expect(console.warn).toBeCalled() expect(tempProps.count).toBe(1) // 驗證功能2,在render中可以直接使用this來訪問props里面的內(nèi)部屬性 expect(document.body.innerHTML).toBe(`1123`) })復制代碼

      分析

      根據(jù)上面的測試用例,分析props的以下內(nèi)容:

    13. 父組件傳遞的參數(shù),可以給到子組件的setup的第一個參數(shù)里面
    14. 在子組件的render函數(shù)中,可以使用this來訪問props的值
    15. 在子組件中修改props會報錯,不允許修改
    16. 解決問題:

      問題1: 想要在子組件的setup函數(shù)中第一個參數(shù),使用props,那么在setup函數(shù)調(diào)用的時候,把當前組件的props傳入到setup函數(shù)中即可 問題2: render中this想要問題,則在上面的那個代理中,在加入一個判斷,key是否在當前instance的props中 問題3: 修改報錯,那就是只能讀,可以使用以前實現(xiàn)的api shallowReadonly來包裹一下既可

      編碼

      1. 在setup函數(shù)調(diào)用的時候,傳入instance.props之前,需要在實例上掛載propsexport function setupComponent(instance) { // 獲取props和children const { props } = instance.vnode // 處理props instance.props = props || {} // ……省略其他 } //2. 在setup中進行調(diào)用時作為參數(shù)賦值 function setupStatefulComponent(instance: any) { // ……省略其他 // 獲取組件的setup const { setup } = Component; if (setup) { // 執(zhí)行setup,并且獲取到setup的結(jié)果,把props使用shallowReadonly進行包裹,則是只讀,不能修改 const setupResult = setup(shallowReadonly(instance.props)); // …… 省略其他 }}// 3. 在propxy中在加入判斷 instance.proxy = new Proxy({}, { get(target, key){ // 判斷當前的key是否存在于instance.setupState當中 if(key in instance.setupState){ return instance.setupState[key] }else if(key in instance.props){ return instance.props[key] }else if(key === ‘$el’){ return instance.vnode.el } } })復制代碼

      做完之后,可以發(fā)現(xiàn)咋們的測試用例是運行沒有毛病的

      組件通信——emit

      上面實現(xiàn)了props,那么emit也是少不了的,那么接下來就來實現(xiàn)下emit

      測試用例

      test(‘測試組件emit’, () => { let count; const Foo = { name: ‘Foo’, render() { return h(‘p’, { class: ‘foo’ }, this.count); }, setup(props, { emit }) { // 1. setup對象的第二個參數(shù)里面,可以結(jié)構(gòu)出emit,并且是一個函數(shù) // 2. emit 函數(shù)可以父組件傳過來的事件 emit(‘click’) // 驗證emit1,可以執(zhí)行父組件的函數(shù) expect(count.value).toBe(2) // 3 emit 可以傳遞參數(shù) emit(‘clickNum’, 5) // 驗證emit傳入?yún)?shù) expect(count.value).toBe(7) // 4 emit 可以使用—的模式 emit(‘click-num’, -5) expect(count.value).toBe(2) } } const app = createApp({ name: ‘App’, render() { return h(‘p’, {}, [ h(Foo, { onClick: this.click, onClickNum: this.clickNum, count: this.count }) ]) }, setup() { const click = () => { count.value++ } count = ref(1) const clickNum = (num) => { count.value = Number(count.value) + Number(num) } return { click, clickNum, count } } }) const appDoc = document.querySelector(‘#app’) app.mount(appDoc); // 驗證掛載 expect(document.body.innerHTML).toBe(`1`) })復制代碼

      分析

      根據(jù)上面的測試用例,可以分析出:

    17. emit 的參數(shù)是在父組件的props里面,并且是以 on + Event的形式
    18. emit 作為setup的第二個參數(shù),并且可以結(jié)構(gòu)出來使用
    19. emit 函數(shù)里面是觸發(fā)事件的,事件名稱,事件名稱可以是小寫,或者是 xxx-xxx的形式
    20. emit 函數(shù)的后續(xù)可以傳入多個參數(shù),作為父組件callback的參數(shù)
    21. 解決辦法: 問題1: emit 是setup的第二個參數(shù),那么可以在setup函數(shù)調(diào)用的時候,傳入第二個參數(shù) 問題2: 關(guān)于emit的第一個參數(shù),可以做條件判斷,把xxx-xxx的形式轉(zhuǎn)成xxxXxx的形式,然后加入on,最后在props中取找,存在則調(diào)用,不存在則不調(diào)用 問題3:emit的第二個參數(shù),則使用剩余參數(shù)即可

      編碼

      // 1. 在setup函數(shù)執(zhí)行的時候,傳入第二個參數(shù) const setupResult = setup(shallowReadonly(instance.props), { emit: instance.emit });// 2. 在setup中傳入第二個參數(shù)的時候,還需要在實例上添加emit屬性哦export function createComponentInstance(vnode) { const instance = { // ……其他屬性 // emit函數(shù) emit: () => { }, } instance.emit = emit.bind(null, instance); function emit(instance, event, …args) { const { props } = instance // 判斷props里面是否有對應(yīng)的事件,有的話執(zhí)行,沒有就不執(zhí)行,處理emit的內(nèi)容,詳情請查看源碼 const key = handlerName(capitalize(camize(event))) const handler = props[key] handler && handler(…args) } return instance}復制代碼

      到此就圓滿成功啦!

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
      用戶投稿
      上一篇 2022年6月19日 15:13
      下一篇 2022年6月19日 15:14

      相關(guān)推薦

      • 短視頻策劃內(nèi)容的3個要點(短視頻策劃內(nèi)容怎么做)

        短視頻在制作時,內(nèi)容框架非常重要。如果直奔主題,然后結(jié)束,聚卓告訴你,這樣的短視頻已經(jīng)過時了?,F(xiàn)在的短視頻需要框架的,但不是任何框架,它需要一種易于理解和消化的框架。而且,現(xiàn)在大多…

        2022年11月27日
      • 存儲過程語法(sql server存儲過程語法)

        今天小編給各位分享存儲過程語法的知識,其中也會對sql server存儲過程語法進行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧! oracle存儲過程基本語法…

        2022年11月26日
      • 全民K歌升級新版本7.0之后,有哪些隱藏功能?

        作者:高百烈來源:知乎 這個功能,舊版并沒有,要升級到全新的全民K歌7.0版本才能發(fā)現(xiàn)。 作為朋友圈當代K歌之王,我費了不少功夫才搶到內(nèi)測版本。有一說一,全民K歌的路子真的很野,新…

        2022年11月25日
      • 上手Reno8 Pro體驗跨屏互聯(lián) 實在太方便!

        11月已經(jīng)來到了月底,在手機品牌又要推出新一年度的新品手機之前,我們來點評一下今年令人驚喜的產(chǎn)品。如OPPO的Reno8 Pro系列,該系列搭載雙芯影像配置獲得了很多消費者的認可?!?/p>

        2022年11月25日
      • 小紅書平臺的一些機制及玩法詳解(小紅書玩法有哪些)

        關(guān)于小紅書 一:小紅書平臺的一些機制 1. 筆記內(nèi)容的CES評分機制 2. 筆記流量入口與長尾效應(yīng) 二:小紅書優(yōu)質(zhì)筆記的特點(分維度、類型分析) 1.筆記的本身架構(gòu)組成 維度 2.…

        2022年11月25日
      • 博客營銷的3大優(yōu)勢解析(博客營銷怎么做)

        不知不覺已經(jīng)寫了24篇文章,加上這篇是第25篇了,都是自己這幾年來用過的營銷方法,如果遇到有些不懂的,我會咨詢我的朋友和同事幫忙,盡量讓每一篇有價值,哪怕是對大家有一點點幫助也行,…

        2022年11月25日
      • 什么是內(nèi)容營銷策略如何策劃一套成功的內(nèi)容營銷策略

        很多時候,營銷人員會在創(chuàng)作營銷內(nèi)容時感到沮喪,這也是很多企業(yè)至今沒用好數(shù)字化營銷工具的重要原因之一。 舉個例子,您可能會花上數(shù)小時期待制作一些令人驚嘆的東西,實際卻是得到很少的受眾…

        2022年11月25日
      • 直播帶貨詳細腳本(直播文案策劃怎么寫)

        短視頻運營策劃方案怎么寫?涉及哪幾個方面? 我在網(wǎng)上看到好多千篇一律的文章,關(guān)于【短視頻運營策劃方案】這一塊,基本都是在講賬號的內(nèi)容本身。 你內(nèi)容做得再好,卻不掌握算法的規(guī)律,能有…

        2022年11月25日
      • 閑魚上怎么賣東西快?閑魚賺錢必知技巧(怎么在閑魚里面賣東西)

        自從閑魚這個平臺出現(xiàn)以后,隨著這些年的發(fā)展,閑魚也成為了很多人開店賺錢的重要途徑。一些新人也想在閑魚上試試水,看看能不能賺到錢。如今閑魚上既可以賣二手閑置物品,也可以賣一些新品,那…

        2022年11月25日
      • 淘寶直播帶貨技巧分享(淘寶直播復制粘貼技巧)

        淘寶是大家喜歡的購物平臺,不少人會自己在淘寶選購,也會在主播直播間購買,價格更實惠,現(xiàn)在很多商家都會開通直播帶貨功能,增加訂單量,那么淘寶直播帶貨有哪些?下面小編為大家?guī)硖詫氈辈ァ?/p>

        2022年11月24日

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時間:周一至周五,10:30-18:30,節(jié)假日休息