深入浅析vue3中的custom renderer特性

本篇文章带大家一起来了解一下vue3的新特性custom renderer。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

深入浅析vue3中的custom renderer特性

【相关推荐:《vue.js教程》】

默认的目标渲染平台

在vue3中允许用户自定义目标渲染平台,以往的版本中目标渲染被局限于浏览器dom平台,而现在可以把 vue 的开发模型扩展到其他平台。点击进入官网Tips:以往解决把 vue 的开发模型扩展到其他平台(Canvas、iOS、Android等等)的方式之一是借助第三方工具例如WEEX(点击进入官网)

我们先来弄懂vue是如何定义默认的目标渲染平台的,也就是说如何将目标渲染到浏览器dom平台上。可以先参考官方图:

1.png

立即学习“前端免费学习笔记(深入)”;

我们先构建起一个初始化的vue3新项目,来一步步分析vue是怎么默认的将目标渲染到浏览器dom平台上,下面是项目中入口文件main.js的代码

import { createApp } from 'vue'import App from './App.vue'createApp(App).mount('#app')

登录后复制最后在来看一下’./APP.vue’的代码:

  
我是根组件实例
export default { name: 'App', components: { }}

登录后复制写这两个文件后我们一运行命令npm run serve,会发现我们写在’./APP.vue’的template已经被渲染到浏览器dom平台上成为了真实的dom元素了,如下图:

2.png

我们应该要发出疑惑,写在’./APP.vue’的template是怎么被渲染到浏览器dom平台上又被转换成真实的dom元素呢?如果让我们自己来做得怎么做到呢?我们可以在入口文件main.js中找到关键线索:

import App from './App.vue'//我们可以打印出App来查看一下console.log(App)

登录后复制我们先打印出App查看一下,这是一个什么信息?如下图:

3.png

在打印出来的App对象里,我们并没有在该对象上找到template属性!我们不禁发出更大的问号,没有了template的信息要怎么做到被转换成真实的dom元素???答案是依靠该对象上的render函数,可以理解为template经过了vue的特殊加工转换为了render函数,并且这个render函数会依照template的有用信息返回一个虚拟DOM(Vnode)我们可以借助工具来验证,如下图:

4.png

如上图,我们可以明确的看到template经过了vue的特殊加工转换为了render函数,并且这个render函数会依照template的有用信息返回一个虚拟DOM(Vnode),关于虚拟DOM的描述可以参考官网点击进入官网我们在发现了这个线索之后,我们可以手动调用App对象下的render函数,来查看一下返回的虚拟DOM到底长什么样子,代码和图片如下:

import App from './App.vue'console.log(App.render());

登录后复制

5.png

如上图,我们可以从返回的虚拟DOM中得到许多有用的信息,这里我用红色框出来的有用信息来简单实现一下如何渲染到浏览器dom平台上并且让其转换成真实的dom元素,代码如下:

//假设这个是虚拟Dom的信息//仅仅是为了演示基本思想const vnode={  type:'div',  children:'123'}const element=document.creatElement(vnode.type)element.innerText=vnode.children//告诉它的出口在哪里 要被渲染到哪里去//这里的出口先假设为#app这个容器document.querySelector('#app').appendChild(element)

登录后复制我们这一整套的逻辑图如下:

6.png

到了这一步我们也做到了如何将写在’./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')

登录后复制

自定义的目标渲染平台

我们在实现自定义的目标渲染平台之前,还得在温习一遍默认的目标渲染平台的流程逻辑图,如下图:

7.png

我们知道canvas也是一个平台,这里就以如何使用vue3渲染到canvas平台上来举例说明。我们先来看成果图:

8.png

我们即将要实现使用vue3的新特性custom renderer来将目标元素渲染到canvas平台上,我们现在实现的逻辑图如下:(注意分支)

9.png

在实现之前,我们必须得先学会几个简单的关于canvas的api。为了快速上手,在这里我使用了pixi.js第三方工具(点击进入官网),pixi.js是基于canvas 的游戏渲染引擎库,借助pixi.js可以省去繁琐的操纵canvas的流程,让我们专心于感受vue3的新特性custom renderer的魅力。下面是使用pixi.js创建canvas并往canvas内添加各种东西的流程图:(最终为了可以直观的看到效果,将canvas呈现在浏览器上(**插入到dom**))

10.png

在vue3的项目使用安装npm i pixi.js后,我们来看一下简单的关于canvas的使用方式,代码和简图如下:

11.png

import {  //初始化  Application,  //创建矩形  Graphics,  //创建图片  Sprite,  //创建文字  Texture,  Text,  TextStyle,  //创建容器  Container,} from "pixi.js";/*通过 new Application来初始化创建canvasoptions规定创建的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平台上了。

自定义渲染到canvas平台上

我们在上一讲已经学会了借助pixi.js对canvas进行简单的操纵,并梳理了自定义渲染到canvas平台上的逻辑,让我们在回顾一下逻辑图,再开始着手使用vue3的新特性custom renderer:

12.png

我们接下来如何操作来完成这一套自定义逻辑呢??有请我们今天的主角登场:custom renderer(点击进入官网)。我们先来重写App.vue里的代码,参考如下:

        export default {  name: 'App',  components: {  }}

登录后复制我们接着重写入口文件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');

登录后复制我们从vue中导出了createRenderer函数,在不配置任何选项的情况下打印出render来查看这到底是个什么东西??如下图:

13.png

我们在打印出的图中可以发现两条熟悉的线索,一个是该render上有createApp方法另一个是该render上有render方法!!!!我们还记得import { createApp } from ‘vue’这一句代码,这一句代码配合createApp(App).mount(‘#app’)就将写在App.vue中的template给渲染到浏览器Dom平台上了,所以vue暴露出来的createApp是已经帮我们封装好逻辑的了。我们现在的任务是调用render下的createApp函数来封装实现我们的逻辑,渲染到canvas平台上,我们先来看下面的代码:

import {createRenderer } from 'vue'import App from './App.vue'//自己要来写逻辑const render=createRenderer({})/*自己要来写逻辑  ---->  render下有createApp函数调用createApp()方法后返回的对象下依旧是有mount()方法的*/render.createApp(这里要填什么).mount(这里又要填什么)

登录后复制

14.png

我们在上面的代码中先不考虑要怎么书写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来初始化创建canvasconst 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()函数都有哪些配置项,如图:

15.png

我们书写createRenderer()函数中的配置项,通过配置项来最终实现我们的逻辑,代码如下:

import { createRenderer } from "vue";import { Graphics } from "pixi.js";const renderer = createRenderer({  // 创建一个元素 --->  抽象的接口函数  // vue执行时会调用这个函数中的逻辑  createElement(type) {    //参考vnode中的type     //因为我们书写了    //所以这里的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) {        /*    向中    传递的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);}

登录后复制

小案例

先放上案例效果图:

16.gif

来看一下目录结构:

17.png

最后温故一下利用custom renderer渲染到canvas平台上的逻辑图:

18.png

我们来看’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’文件的代码:

  export default {};

登录后复制我们最后来看App.vue文件的代码:

        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 {      game.ticker.remove(handleTicker)      game.ticker.remove(handleTicker2)    })    return{      circle,      handleTicker,      x,      y    }  }}

登录后复制

原文地址:https://juejin.cn/post/6910470057961193480作者:林子酱

更多编程相关知识,请访问:编程视频!!

以上就是深入浅析vue3中的custom renderer特性的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/3020136.html

(0)
上一篇 2025年3月13日 05:34:12
下一篇 2025年3月13日 05:34:28

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Vue如何封装Echarts图表

    在开始之前,我们先按照正常的组件注册流程,在项目components目录中新建一个名为radar-chart的组件,然后在一个demo页面引入该组件使用。 新建的 radar-chart 组件内容: // radar-chart.vue (…

    2025年3月13日
    200
  • 浅谈Vue中v-for,key取值影响过渡效果和动画效果(代码详解)

    之前的文章《教你怎么使用Vue实现动画效果(附代码)》中,给大家介绍了怎么使用Vue实现动画效果。下面本篇文章给大家了解一下浅谈Vue中key取值影响过渡效果和动画效果,有需要的朋友可以参考一下,希望对你们有帮助。 关于Vue.js的v-f…

    2025年3月13日
    200
  • 浅析Vue中入口缓存的问题(代码分享)

    之前的文章《你值得了解的HTTP缓存机制(代码详解)》中,给大家了解了HTTP缓存机制。下面本篇文章给大家了解Vue中入口缓存的问题,伙伴们来看看吧。 关于web的缓存策略,推荐这篇文章:Http缓存机制 在开发时候经常遇到一个问题,我们根…

    2025年3月13日
    200
  • 怎么看vuejs是否安装成功

    看vuejs是否安装成功的方法:1、使用组合键“windows+R”打开“运行”窗口,输入“cmd”,点击“确定”;2、在打开的cmd命令窗口中,执行命令“vue -V”,如果输出版本号则表示vuejs安装成功,反之则安装不成功。 本教程操…

    2025年3月13日
    200
  • vuejs怎么关闭弹窗

    vuejs关闭弹窗的方法:1、创建html代码结构;2、判断所点击的区域是否在“.mask_popup”中;3、通过“hideMaskPopup(e){…}”关闭弹窗即可。 本文操作环境:windows7系统、vue2.5.17…

    2025年3月13日
    200
  • vuejs是国产框架吗

    vuejs算是国产框架,因为vuejs框架的作者是拥有中国国籍的尤雨溪,该作者属于独立开源开发者,目前全职开发和维护Vue.js,所以说vuejs是国产框架。 本文操作环境:windows7系统、vue2.5.17版,DELL G3电脑。 …

    2025年3月13日
    200
  • vuejs的生命周期是什么

    vuejs的生命周期是指vue实例对象从创建之初到销毁的过程,vue所有功能的实现都是围绕其生命周期进行的,在生命周期的不同阶段调用对应的钩子函数可以实现组件数据管理和DOM渲染两大重要功能。 本教程操作环境:windows7系统、vue2…

    2025年3月13日 编程技术
    200
  • 怎么在idea创建vuejs项目

    创建方法:1、安装Node;2、打开idea,点击“Create New Project”-“Static Web”,填写项目名,点击“Finis”;3、打开idea的Terminal,执行指令来安装vue脚手架工具、初始化vue项目即可。…

    2025年3月13日 编程技术
    200
  • vuejs怎么实现全局状态管理

    在vuejs中可以利用vuex实现全局状态管理;Vuex是一个专为Vue.js应用程序开发的状态管理模式,可以用来管理全局数据,可以管理复杂应用的数据状态,比如兄弟组件的通信、多层嵌套的组件的传值等等。 本教程操作环境:windows7系统…

    2025年3月13日
    200
  • vuejs有哪些使用场景

    vuejs的使用场景:1、单页面应用程序;2、移动端开发,可以结合i-view、Element UI等一些成熟的前端UI库一起开发;3、维护较少,组件复用要求不高的项目;4、具有复杂交互逻辑的前端应用等。 本教程操作环境:windows7系…

    2025年3月13日
    200

发表回复

登录后才能评论