Home > Article > Web Front-end > An in-depth analysis of the custom renderer features in vue3
This article takes everyone to learn about vue3’s new feature rendercustomer. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.
[Related recommendation: "vue.js Tutorial"]
Canvas, iOS, Android, etc.
) was to use the third Third-party tools such as WEEX (Click to enter the official website)Let’s first understand how vue defines the default target rendering platform, that is, how to render the target Go to the browser dom platform. You can refer to the official picture first:
import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
'./APP. The code of vue'
: <template> <div>我是根组件实例</div> </template> <script> export default { name: 'App', components: { } } </script>
npm run serve
, we will find that we wrote in ' The template of ./APP.vue'
has been rendered to the browser dom platform and has become a real dom element, as shown below: './APP.vue'
is rendered to the browser dom platform and converted into a real dom element ?How can we do it if we do it ourselves? We can find the key clue in the entry file main.js
: import App from './App.vue' //我们可以打印出App来查看一下 console.log(App)
(Vnode )
(Vnode)
according to the useful information of the template. For a description of the virtual DOM, please refer to the official websiteClick to enter the official website
import App from './App.vue' console.log(App.render());
//假设这个是虚拟Dom的信息 //仅仅是为了演示基本思想 const vnode={ type:'div', children:'123' } const element=document.creatElement(vnode.type) element.innerText=vnode.children //告诉它的出口在哪里 要被渲染到哪里去 //这里的出口先假设为#app这个容器 document.querySelector('#app').appendChild(element)
'./APP.vue'
的template渲染到浏览器dom平台上并且转换成真实的dom元素(虽然写的代码很菜
),可是这一套逻辑vue已经帮我们实现了,我们现在再来看入口文件main.js的代码:/* //createApp的作用是将传入的组件转换为真实的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')
注意分支
)pixi.js
第三方工具(点击进入官网),pixi.js
是基于canvas 的游戏渲染引擎库,借助pixi.js
可以省去繁琐的操纵canvas的流程,让我们专心于感受vue3的新特性custom renderer的魅力。pixi.js
创建canvas并往canvas内添加各种东西的流程图:(最终为了可以直观的看到效果,将canvas呈现在浏览器上(**插入到dom**)
)npm i pixi.js
后,我们来看一下简单的关于canvas的使用方式,代码和简图如下:import { //初始化 Application, //创建矩形 Graphics, //创建图片 Sprite, //创建文字 Texture, Text, TextStyle, //创建容器 Container, } from "pixi.js"; /* 通过 new Application来初始化创建canvas options规定创建的canvas的宽和高 */ const game = new Application({ width: 500, height: 500, }); /* 为了可以直观的看到效果 将canvas呈现在浏览器上(**插入到dom**) game.view是canvas视图元素 */ document.body.append(game.view); /* 创建一个矩形 rect.x和rect.y是设置矩形的初始位置偏移量 //单独(独自)添加矩形到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; /* 创建图片 //单独(独自)添加矩形到canvas容器上使用下一行命令 game.stage.addChild(img); */ import logo from "./assets/logo.png"; const img = new Sprite(); //指定后才允许给图片添加点击事件 img.interactive = true; //指定图片的src路径 img.texture = Texture.from(logo); //添加帧循环 会一直执行handleTicker事件直至删除该帧循环 game.ticker.add(handleTicker); //handleTicker事件 令图片的x偏移量不断增加 const handleTicker = () => {img.x++}; /* pixi的点击事件名 必须配合img.interactive = true才能允许被点击 */ img.on("pointertap", () => { game.ticker.remove(handleTicker); }); /* 创建文本 //单独(独自)添加矩形到canvas容器上使用下一行命令 game.stage.addChild(text); */ const text = new Text("heihei"); text.style = new TextStyle({ fill: "red", }); text.x = 380; /* 创建容器 //容器中可以放图片、文字、矩形等等 //容器是一个大的整体 //将容器添加到canvas上的话 //容器中的内容也会一并被添加到canvas上 //即下一行代码 game.stage.addChild(box); */ const box = new Container(); box.addChild(text); box.addChild(img); //统一的移动它们的位置 box.x = 2 /* 如果你想要把你创建的东西渲染到canvas容器内的话 必须把东西通过game.stage.addChild的方式添加进去才能显示 */ //单独添加以添加矩形为例 game.stage.addChild(rect); //添加一个容器 //(容器中可以包含图片、文字等等也会被一并添加上canvas) game.stage.addChild(box);
pixi.js
学会了对canvas的简单操纵,接下来我们就要使用vue3的custom renderer来将元素渲染到canvas平台上了。pixi.js
对canvas进行简单的操纵,并梳理了自定义渲染到canvas平台上的逻辑,让我们在回顾一下逻辑图,再开始着手使用vue3的新特性custom renderer:App.vue
里的代码,参考如下:<template> <!-- 这里的circle和rect是自定义标签 不是组件不是组件不是组件 --> <circle x="50" y="50"></circle> </template> <script> export default { name: 'App', components: { } } </script>
main.js
中的代码。参考如下:/* 默认的渲染到浏览器dom平台上的代码 import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app') */ /*自定义渲染到canvas平台上 createRenderer就是告诉vue我要自定义渲染平台了 自定义渲染器可以传入特定于平台的类型 */ import { createRenderer } from "vue"; //我们不急着往createRenderer添加相关配置 //我们先打印render查看这个到底是个什么 const render=createRenderer({}) console.log(render,'render');
import { createApp } from 'vue'
这一句代码,这一句代码配合createApp(App).mount('#app')
就将写在App.vue
中的template给渲染到浏览器Dom平台上了,所以vue暴露出来的createApp是已经帮我们封装好逻辑的了。import {createRenderer } from 'vue' import App from './App.vue' //自己要来写逻辑 const render=createRenderer({}) /* 自己要来写逻辑 ----> render下有createApp函数 调用createApp()方法后 返回的对象下依旧是有mount()方法的 */ render.createApp(这里要填什么).mount(这里又要填什么)
createRenderer()
函数中的配置项封装逻辑,先来考虑render.createApp(这里要填什么).mount(这里又要填什么)
这两个空要怎么填的问题?createApp(App).mount('#app')
便可以知道第一个空应该要填的是根组件
,在这里我们同样填的是import App from './App.vue'
导出的App,第二个空应该要填的是根容器
,我们需要的是渲染到canvas平台上,所以我们的根容器得是game.stage
(这里的game.stage是经过pixi.js初始化后的canvas容器
),代码如下:import { Application } from "pixi.js"; //通过 new Application来初始化创建canvas const game = new Application({ width: 750, height: 750, }); // 为了可以直观的看到效果 // 将canvas呈现在浏览器上(**插入到dom**) document.body.append(game.view); /* 导出canvas容器供 render.createApp(这里要填什么).mount(getRootContainer()) 使用 */ export function getRootContainer() { return game.stage; }
createRenderer()
函数中的配置项,通过配置项来最终实现我们的逻辑把在App.vue
中重写的template渲染到canvas平台上,来看一下createRenderer()
函数都有哪些配置项,如图:createRenderer()
函数中的配置项,通过配置项来最终实现我们的逻辑,代码如下:import { createRenderer } from "vue"; import { Graphics } from "pixi.js"; const renderer = createRenderer({ // 创建一个元素 ---> 抽象的接口函数 // vue执行时会调用这个函数中的逻辑 createElement(type) { //参考vnode中的type //因为我们书写了<circle></circle> //所以这里的type会有circle console.log(type); let element; //调用canvas api来创建矩形、圆形、图片等等 //层级关系是后添加的在上面 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); //第三个参数是圆的半径 element.drawCircle(0, 0, 50); element.endFill(); break; } //最终一定要返回element否则下方的函数接收不到 return element; }, patchProp(el, key, prevValue, nextValue) { /* 向<circle x="50" y="50"></circle>中 传递的props能在这里获取到 利用这点可以去改变canvas容器中具体东西的行为 比如改变位置、添加点击事件、等等 如果传递的是响应式数据的话 当响应式数据变更时canvas上的具体东西也会实时响应更新 比如实时响应移动改变位置等等 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; } }, // 插入到对应的容器内 insert(el, parent) { console.log(el, parent); /* el是上面的createElement函数中返回的element parent是render.createApp(App).mount(getRootContainer())中 getRootContainer()的返回值即canvas容器game.stage; 在该函数中把创建的东西(矩形、图形、圆形等等)添加到canvas容器内 即game.stage.addChild(element); */ parent.addChild(el); }, }); /* 因为vue中自己暴露了默认可以渲染到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); }
先放上案例效果图:
'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": //创建球形 element = new Graphics(); element.beginFill(0xffff00); element.drawCircle(0, 0, 50); element.endFill(); break; } return element; }, patchProp(el, key, prevValue, nextValue) { switch (key) { //根据传递的props初始化‘具体东西元素’的位置 //如果props是响应式数据那么在该响应式数据改变时 //会被这里拦截到并实时响应更新视图位置 case "x": el.x = nextValue; break; case "y": el.y = nextValue; break; default: break; } }, insert(el, parent) { console.log(el, parent); //添加到canvas容器内 parent.addChild(el); }, }); export function createApp(rootComponent) { return renderer.createApp(rootComponent); }
'componenets/Circle.vue'
文件的代码:<template> <circle></circle> </template> <script> export default { }; </script> <style></style>
App.vue
文件的代码:<template> <Circle :x="x" :y="y" ref="circle"></Circle> </template> <script> import Circle from "./components/Circle"; import {getGame} from './game/index'; import {ref,onMounted, onUnmounted} from 'vue'; export default { name: "App", components: { Circle, }, setup() { let x=ref('50') let y=ref('50') const game=getGame() onMounted(()=>{ // console.log(circle,'circle'); // console.log(game,'game'); // console.log(circle.value.$el,'xx'); game.ticker.add(handleTicker); }); const handleTicker = function(){ // console.log(circle.value.$el); circle.value.$el.x+=10 if(circle.value.$el.x>700){ game.ticker.remove(handleTicker); game.ticker.add(handleTicker2); } } const handleTicker2 = function(){ // console.log(circle.value.$el); circle.value.$el.x-=10 if(circle.value.$el.x<50){ game.ticker.remove(handleTicker2) game.ticker.add(handleTicker); } }; // console.log(circle,'circle'); let circle=ref(null) onUnmounted(() => { game.ticker.remove(handleTicker) game.ticker.remove(handleTicker2) }) return{ circle, handleTicker, x, y } } } </script> <style> </style>
原文地址:https://juejin.cn/post/6910470057961193480
作者:林子酱
更多编程相关知识,请访问:编程视频!!
The above is the detailed content of An in-depth analysis of the custom renderer features in vue3. For more information, please follow other related articles on the PHP Chinese website!