本篇內(nèi)容主要講解“vue3中的custom renderer特性有什么用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“vue3中的custom renderer特性有什么用”吧!
為企業(yè)提供做網(wǎng)站、成都做網(wǎng)站、網(wǎng)站優(yōu)化、成都全網(wǎng)營銷、競價托管、品牌運營等營銷獲客服務(wù)。創(chuàng)新互聯(lián)擁有網(wǎng)絡(luò)營銷運營團(tuán)隊,以豐富的互聯(lián)網(wǎng)營銷經(jīng)驗助力企業(yè)精準(zhǔn)獲客,真正落地解決中小企業(yè)營銷獲客難題,做到“讓獲客更簡單”。自創(chuàng)立至今,成功用技術(shù)實力解決了企業(yè)“網(wǎng)站建設(shè)、網(wǎng)絡(luò)品牌塑造、網(wǎng)絡(luò)營銷”三大難題,同時降低了營銷成本,提高了有效客戶轉(zhuǎn)化率,獲得了眾多企業(yè)客戶的高度認(rèn)可!
在vue3中允許用戶自定義目標(biāo)渲染平臺,以往的版本中目標(biāo)渲染被局限于瀏覽器dom平臺,而現(xiàn)在可以把 vue 的開發(fā)模型擴(kuò)展到其他平臺。點擊進(jìn)入官網(wǎng)
Tips:以往解決把 vue 的開發(fā)模型擴(kuò)展到其他平臺(Canvas、iOS、Android等等
)的方式之一是借助第三方工具例如WEEX(點擊進(jìn)入官網(wǎng))
我們先來弄懂vue是如何定義默認(rèn)的目標(biāo)渲染平臺的,也就是說如何將目標(biāo)渲染到瀏覽器dom平臺上??梢韵葏⒖脊俜綀D:
我們先構(gòu)建起一個初始化的vue3新項目,來一步步分析vue是怎么默認(rèn)的將目標(biāo)渲染到瀏覽器dom平臺上,下面是項目中入口文件main.js的代碼
import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
最后在來看一下'./APP.vue'
的代碼:
我是根組件實例
寫這兩個文件后我們一運行命令npm run serve
,會發(fā)現(xiàn)我們寫在'./APP.vue'
的template已經(jīng)被渲染到瀏覽器dom平臺上成為了真實的dom元素了,如下圖:
我們應(yīng)該要發(fā)出疑惑,寫在'./APP.vue'
的template是怎么被渲染到瀏覽器dom平臺上又被轉(zhuǎn)換成真實的dom元素呢?如果讓我們自己來做得怎么做到呢?我們可以在入口文件main.js
中找到關(guān)鍵線索:
import App from './App.vue' //我們可以打印出App來查看一下 console.log(App)
我們先打印出App查看一下,這是一個什么信息?如下圖:
在打印出來的App對象里,我們并沒有在該對象上找到template屬性!我們不禁發(fā)出更大的問號,沒有了template的信息要怎么做到被轉(zhuǎn)換成真實的dom元素???答案是依靠該對象上的render函數(shù),可以理解為template經(jīng)過了vue的特殊加工轉(zhuǎn)換為了render函數(shù),并且這個render函數(shù)會依照template的有用信息返回一個虛擬DOM(Vnode)
我們可以借助工具來驗證,如下圖:
如上圖,我們可以明確的看到template經(jīng)過了vue的特殊加工轉(zhuǎn)換為了render函數(shù),并且這個render函數(shù)會依照template的有用信息返回一個虛擬DOM(Vnode)
,關(guān)于虛擬DOM的描述可以參考官網(wǎng)點擊進(jìn)入官網(wǎng)
我們在發(fā)現(xiàn)了這個線索之后,我們可以手動調(diào)用App對象下的render函數(shù),來查看一下返回的虛擬DOM到底長什么樣子,代碼和圖片如下:
import App from './App.vue' console.log(App.render());
如上圖,我們可以從返回的虛擬DOM中得到許多有用的信息,這里我用紅色框出來的有用信息來簡單實現(xiàn)一下如何渲染到瀏覽器dom平臺上并且讓其轉(zhuǎn)換成真實的dom元素,代碼如下:
//假設(shè)這個是虛擬Dom的信息 //僅僅是為了演示基本思想 const vnode={ type:'div', children:'123' } const element=document.creatElement(vnode.type) element.innerText=vnode.children //告訴它的出口在哪里 要被渲染到哪里去 //這里的出口先假設(shè)為#app這個容器 document.querySelector('#app').appendChild(element)
我們這一整套的邏輯圖如下:
到了這一步我們也做到了如何將寫在'./APP.vue'
的template渲染到瀏覽器dom平臺上并且轉(zhuǎn)換成真實的dom元素(雖然寫的代碼很菜
),可是這一套邏輯vue已經(jīng)幫我們實現(xiàn)了,我們現(xiàn)在再來看入口文件main.js的代碼:
/* //createApp的作用是將傳入的組件轉(zhuǎn)換為真實的Dom元素 //核心思想就是剛才寫的 //const element=document.creatElement(vnode.type) //element.innerText=vnode.children */ import { createApp } from 'vue' import App from './App.vue' /* //mount的作用是告訴它的出口在哪里、要被渲染到哪里去 //核心思想就是剛才寫的 //document.querySelector('#app').appendChild(element) */ createApp(App).mount('#app')
我們在實現(xiàn)自定義的目標(biāo)渲染平臺之前,還得在溫習(xí)一遍默認(rèn)的目標(biāo)渲染平臺的流程邏輯圖,如下圖:
我們知道canvas也是一個平臺,這里就以如何使用vue3渲染到canvas平臺上來舉例說明。我們先來看成果圖:
我們即將要實現(xiàn)使用vue3的新特性custom renderer來將目標(biāo)元素渲染到canvas平臺上,我們現(xiàn)在實現(xiàn)的邏輯圖如下:(注意分支
)
在實現(xiàn)之前,我們必須得先學(xué)會幾個簡單的關(guān)于canvas的api。為了快速上手,在這里我使用了pixi.js
第三方工具(點擊進(jìn)入官網(wǎng)),pixi.js
是基于canvas 的游戲渲染引擎庫,借助pixi.js
可以省去繁瑣的操縱canvas的流程,讓我們專心于感受vue3的新特性custom renderer的魅力。
下面是使用pixi.js
創(chuàng)建canvas并往canvas內(nèi)添加各種東西的流程圖:(最終為了可以直觀的看到效果,將canvas呈現(xiàn)在瀏覽器上(**插入到dom**)
)
在vue3的項目使用安裝npm i pixi.js
后,我們來看一下簡單的關(guān)于canvas的使用方式,代碼和簡圖如下:
import { //初始化 Application, //創(chuàng)建矩形 Graphics, //創(chuàng)建圖片 Sprite, //創(chuàng)建文字 Texture, Text, TextStyle, //創(chuàng)建容器 Container, } from "pixi.js"; /* 通過 new Application來初始化創(chuàng)建canvas options規(guī)定創(chuàng)建的canvas的寬和高 */ const game = new Application({ width: 500, height: 500, }); /* 為了可以直觀的看到效果 將canvas呈現(xiàn)在瀏覽器上(**插入到dom**) game.view是canvas視圖元素 */ document.body.append(game.view); /* 創(chuàng)建一個矩形 rect.x和rect.y是設(shè)置矩形的初始位置偏移量 //單獨(獨自)添加矩形到canvas容器上使用下一行命令 game.stage.addChild(rect); */ const rect = new Graphics(); rect.beginFill(0xffff00); rect.drawRect(0, 0, 50, 50); rect.endFill(); rect.x = 50; rect.y = 50; /* 創(chuàng)建圖片 //單獨(獨自)添加矩形到canvas容器上使用下一行命令 game.stage.addChild(img); */ import logo from "./assets/logo.png"; const img = new Sprite(); //指定后才允許給圖片添加點擊事件 img.interactive = true; //指定圖片的src路徑 img.texture = Texture.from(logo); //添加幀循環(huán) 會一直執(zhí)行handleTicker事件直至刪除該幀循環(huán) game.ticker.add(handleTicker); //handleTicker事件 令圖片的x偏移量不斷增加 const handleTicker = () => {img.x++}; /* pixi的點擊事件名 必須配合img.interactive = true才能允許被點擊 */ img.on("pointertap", () => { game.ticker.remove(handleTicker); }); /* 創(chuàng)建文本 //單獨(獨自)添加矩形到canvas容器上使用下一行命令 game.stage.addChild(text); */ const text = new Text("heihei"); text.style = new TextStyle({ fill: "red", }); text.x = 380; /* 創(chuàng)建容器 //容器中可以放圖片、文字、矩形等等 //容器是一個大的整體 //將容器添加到canvas上的話 //容器中的內(nèi)容也會一并被添加到canvas上 //即下一行代碼 game.stage.addChild(box); */ const box = new Container(); box.addChild(text); box.addChild(img); //統(tǒng)一的移動它們的位置 box.x = 2 /* 如果你想要把你創(chuàng)建的東西渲染到canvas容器內(nèi)的話 必須把東西通過game.stage.addChild的方式添加進(jìn)去才能顯示 */ //單獨添加以添加矩形為例 game.stage.addChild(rect); //添加一個容器 //(容器中可以包含圖片、文字等等也會被一并添加上canvas) game.stage.addChild(box);
我們現(xiàn)在借助pixi.js
學(xué)會了對canvas的簡單操縱,接下來我們就要使用vue3的custom renderer來將元素渲染到canvas平臺上了。
我們在上一講已經(jīng)學(xué)會了借助pixi.js
對canvas進(jìn)行簡單的操縱,并梳理了自定義渲染到canvas平臺上的邏輯,讓我們在回顧一下邏輯圖,再開始著手使用vue3的新特性custom renderer:
我們接下來如何操作來完成這一套自定義邏輯呢??有請我們今天的主角登場:custom renderer(點擊進(jìn)入官網(wǎng))。
我們先來重寫App.vue
里的代碼,參考如下:
我們接著重寫入口文件main.js
中的代碼。參考如下:
/* 默認(rèn)的渲染到瀏覽器dom平臺上的代碼 import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app') */ /*自定義渲染到canvas平臺上 createRenderer就是告訴vue我要自定義渲染平臺了 自定義渲染器可以傳入特定于平臺的類型 */ import { createRenderer } from "vue"; //我們不急著往createRenderer添加相關(guān)配置 //我們先打印render查看這個到底是個什么 const render=createRenderer({}) console.log(render,'render');
我們從vue中導(dǎo)出了createRenderer函數(shù),在不配置任何選項的情況下打印出render來查看這到底是個什么東西??如下圖:
我們在打印出的圖中可以發(fā)現(xiàn)兩條熟悉的線索,一個是該render上有createApp方法另一個是該render上有render方法!!!!
我們還記得import { createApp } from 'vue'
這一句代碼,這一句代碼配合createApp(App).mount('#app')
就將寫在App.vue
中的template給渲染到瀏覽器Dom平臺上了,所以vue暴露出來的createApp是已經(jīng)幫我們封裝好邏輯的了。
我們現(xiàn)在的任務(wù)是調(diào)用render下的createApp函數(shù)來封裝實現(xiàn)我們的邏輯,渲染到canvas平臺上,我們先來看下面的代碼:
import {createRenderer } from 'vue' import App from './App.vue' //自己要來寫邏輯 const render=createRenderer({}) /* 自己要來寫邏輯 ----> render下有createApp函數(shù) 調(diào)用createApp()方法后 返回的對象下依舊是有mount()方法的 */ render.createApp(這里要填什么).mount(這里又要填什么)
我們在上面的代碼中先不考慮要怎么書寫createRenderer()
函數(shù)中的配置項封裝邏輯,先來考慮render.createApp(這里要填什么).mount(這里又要填什么)
這兩個空要怎么填的問題?
我們參考createApp(App).mount('#app')
便可以知道第一個空應(yīng)該要填的是根組件
,在這里我們同樣填的是import App from './App.vue'
導(dǎo)出的App,第二個空應(yīng)該要填的是根容器
,我們需要的是渲染到canvas平臺上,所以我們的根容器得是game.stage
(這里的game.stage是經(jīng)過pixi.js初始化后的canvas容器
),代碼如下:
import { Application } from "pixi.js"; //通過 new Application來初始化創(chuàng)建canvas const game = new Application({ width: 750, height: 750, }); // 為了可以直觀的看到效果 // 將canvas呈現(xiàn)在瀏覽器上(**插入到dom**) document.body.append(game.view); /* 導(dǎo)出canvas容器供 render.createApp(這里要填什么).mount(getRootContainer()) 使用 */ export function getRootContainer() { return game.stage; }
緊接著我們就來書寫createRenderer()
函數(shù)中的配置項,通過配置項來最終實現(xiàn)我們的邏輯把在App.vue
中重寫的template渲染到canvas平臺上,來看一下createRenderer()
函數(shù)都有哪些配置項,如圖:
我們書寫createRenderer()
函數(shù)中的配置項,通過配置項來最終實現(xiàn)我們的邏輯,代碼如下:
import { createRenderer } from "vue"; import { Graphics } from "pixi.js"; const renderer = createRenderer({ // 創(chuàng)建一個元素 ---> 抽象的接口函數(shù) // vue執(zhí)行時會調(diào)用這個函數(shù)中的邏輯 createElement(type) { //參考vnode中的type //因為我們書寫了//所以這里的type會有circle console.log(type); let element; //調(diào)用canvas api來創(chuàng)建矩形、圓形、圖片等等 //層級關(guān)系是后添加的在上面 switch (type) { case "rect": element = new Graphics(); element.beginFill(0xff0000); element.drawRect(0, 0, 500, 500); element.endFill(); break; case "circle": element = new Graphics(); element.beginFill(0xffff00); //第三個參數(shù)是圓的半徑 element.drawCircle(0, 0, 50); element.endFill(); break; } //最終一定要返回element否則下方的函數(shù)接收不到 return element; }, patchProp(el, key, prevValue, nextValue) { /* 向 中 傳遞的props能在這里獲取到 利用這點可以去改變canvas容器中具體東西的行為 比如改變位置、添加點擊事件、等等 如果傳遞的是響應(yīng)式數(shù)據(jù)的話 當(dāng)響應(yīng)式數(shù)據(jù)變更時canvas上的具體東西也會實時響應(yīng)更新 比如實時響應(yīng)移動改變位置等等 console.log(el,'可以得到該對象'); console.log(key,'可以得到x和y'); console.log(nextValue,'可以得到50'); */ switch (key) { case "x": el.x = nextValue; break; case "y": el.y = nextValue; break; default: break; } }, // 插入到對應(yīng)的容器內(nèi) insert(el, parent) { console.log(el, parent); /* el是上面的createElement函數(shù)中返回的element parent是render.createApp(App).mount(getRootContainer())中 getRootContainer()的返回值即canvas容器game.stage; 在該函數(shù)中把創(chuàng)建的東西(矩形、圖形、圓形等等)添加到canvas容器內(nèi) 即game.stage.addChild(element); */ parent.addChild(el); }, }); /* 因為vue中自己暴露了默認(rèn)可以渲染到dom平臺上的createApp方法 我們模仿這個行為也暴露一個自己封裝好的渲染到canvas平臺上的createApp方法 只需要通過以下四行代碼就可以開始使用了 import {createApp} from './runtime-canvas/index'; import App from './App.vue'; import {getRootContainer} from './game/index'; createApp(App).mount(getRootContainer()); */ export function createApp(rootComponent) { return renderer.createApp(rootComponent); }
先放上案例效果圖:
來看一下目錄結(jié)構(gòu):
最后溫故一下利用custom renderer渲染到canvas平臺上的邏輯圖:
我們來看'main.js'
文件的代碼:
//封裝自定義渲染到canvas平臺上的邏輯 import { createApp } from "./runtime-canvas"; import App from "./App.vue"; //初始化canvas的容器 import { getRootContainer } from "./game"; createApp(App).mount(getRootContainer());
我們來看"./game/index.js"
文件的代碼:
import { Application } from "pixi.js"; const game = new Application({ width: 750, height: 750, }); document.body.append(game.view); export function getRootContainer() { return game.stage; } export function getGame() { return game }
我們緊接著看"./runtime-canvas/index.js"
文件的代碼:
import { createRenderer } from "vue"; import { Graphics } from "pixi.js"; const renderer = createRenderer({ createElement(type) { let element; switch (type) { case "rect": element = new Graphics(); element.beginFill(0xff0000); element.drawRect(0, 0, 500, 500); element.endFill(); break; case "circle": //創(chuàng)建球形 element = new Graphics(); element.beginFill(0xffff00); element.drawCircle(0, 0, 50); element.endFill(); break; } return element; }, patchProp(el, key, prevValue, nextValue) { switch (key) { //根據(jù)傳遞的props初始化‘具體東西元素’的位置 //如果props是響應(yīng)式數(shù)據(jù)那么在該響應(yīng)式數(shù)據(jù)改變時 //會被這里攔截到并實時響應(yīng)更新視圖位置 case "x": el.x = nextValue; break; case "y": el.y = nextValue; break; default: break; } }, insert(el, parent) { console.log(el, parent); //添加到canvas容器內(nèi) parent.addChild(el); }, }); export function createApp(rootComponent) { return renderer.createApp(rootComponent); }
我們再看'componenets/Circle.vue'
文件的代碼:
我們最后來看App.vue
文件的代碼:
到此,相信大家對“vue3中的custom renderer特性有什么用”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!