由于小程序的开发起来比较原始复杂且繁琐,跟我们主流的开发方式差距很大,所以为了提高我们开发小程序的效率,市面上出现过很多的小程序的框架:mpvue,Taro,uni-app 等等,这些框架或多或少地将我们带到现代化的开发方式中来,他们可以让你使用 React 或者 Vue 来开发小程序。今天就分享一个如何利用 Vue 3.0 来构建一个小程序的框架。
1
Vue3 的新特性主要有 Composition API
、Teleport
、Fragments
和 <script setup /> & <style vars />
等。
Vue2.x 基于 Option API(选项 API )
构建组件,一般来说组件拥有 data、methods、computed 等选项。这是一种属性相互隔离的模式,好处是各属性内容分离开,对于新手来说比较友好。
但对于大型项目来说,为了修改某个功能,可能需要在一个文件中来回翻页。Vue3 增加了 Composition API 方式(组合 API )
,基于 reactivity(响应式)
的思想进行组件构建,将逻辑封装到函数中,可以实现类似 React Hooks 的逻辑组合和重用。
对于大型项目,代码按照具体功能划分,而不是分散在不同的生命周期中,逻辑更加一目了然。
Teleport 功能,使得我们可以将全屏的组件(例如 Toast)移到 Vue APP 节点外,而不需要在 UI 界面上修改其他组件样式,方便实现全屏蒙层、浮层弹窗等效果。
Vue2.x 版本中,<template />
标签下不支持放置多个组件,这个限制在 Vue3 中不再存在。这点比较好理解,下述组件设计在 Vue3 中是没有问题的:
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
4. 实验性质的语法糖<script setup>、<style vars>
a、<script setup>
:用于在 SFC 中使用 Composition API
的语法糖,改善在单个文件组件中使用 Composition API 时的体验。
b、<style vars>
: SFC 中状态驱动的 CSS 变量,它提供了直接的 CSS 配置和封装,支持将组件状态驱动的CSS变量注入到“单个文件组件”样式中。
2
小程序
要开发一个小程序的页面基本上我们只需要四个文件:
index.js 就是我们写代码逻辑的地方。
index.ttml 是我们写视图模板的地方。
index.json
配置小程序页面和组件的地方,暂时不列出参数,但是一定要有这个文件。
顾名思义,就是写样式的地方,类似于 CSS。
小程序为了封装的方便,可以先提前定义一个模板,然后再需要的地方引入模板即可,有点像 ejs 和 pug 的 import template 的用法
动态模板
上面说到,小程序里面不能动态的修改 DOM 节点,只能提前定义好 template,然后通过 setData 的形式去修改视图。
但是小程序又有个比较动态的特性,叫做动态选择模板。
// 使用这个模板 <template is="{{type}}" data="{{item: item}}"/>
上面 is 属性的 type 就是动态的,它是个变量,可以根据 type 的值来选择不同的模板,比如 type 为 view 时,就会渲染我们提前定义好的 view template。
重头戏来了,我们该如何利用 Vue 3.0 方便的自定义渲染层 结合小程序的动态选择模板的特性来去写一个小程序的框架呢?
import {
createRenderer,
CreateAppFunction,
} from '@vue/runtime-core';
export const { render, createApp: baseCreateApp } = createRenderer({
patchProp, // 修改 props 的函数
...nodeOps, // 修改 dom 节点的函数
});
我们可以看到`createRenderer`
函数需要两个参数,一个是patchProp,一个是nodeOps。
nodeOps 代表着修改 node 节点的一些操作,从而可以去改变视图,比如在 Vue 3.0 的浏览器环境中,是这么写的:
实际上 Vue 不管数据怎么变化,要将数据显示到视图上都是调用了 DOM 的一些 API,像上面的 doc.createElement 和 doc.createTextNode 等等。
是由于小程序的限制,我们不能直接像浏览器环境一样去修改 DOM,那我们可以先模仿浏览器的环境,创造出一个虚拟的DOM,我们叫做 VNode。
可以看到我们创建的 VNode 类似于 DOM,也有一些操作 Node 节点的方法,最终生成一个 Node 树。我们就可以仿照vue 浏览器环境的 nodeOps 写法,先去修改我们的 VNode,在修改 Node 节点的同时里面我们可以去调用小程序的 setData 方法。
光是创造出 VNode 还不够,我们得让它渲染到小程序里面去,小程序要先渲染出数据必须是提前在 data 属性里面定义的数据,而且只能是普通的数据类型。
toJSON 方法就是可以将一个 VNode 给格式化成普通的对象,让小程序可以渲染出数据。
接口类型如下:
是不是跟 VDOM 的结构很熟悉?
我们可以看到在我们定义的 VNode 里面,里面有个 path() 方法,这个方法就是获取 Node 节点在整个节点树的一个路径,然后可以利用 path 去修改某一个特定的 Node 节点。
我们写的代码肯定是Vue的代码,不是上面的模板代码,那么Vue的代码改怎么样去编译到上面的模板代码呢?
先看一下整体架构图:
如果我们写的业务代码是常见的 vue 指令模板模式,那么我们可以在底层使用 @vue/compile-core 来 parse Vue 的 template,然后遍历 parse 后的 AST,收集其中用到的 tag 和 props。
如果我们写的业务代码是 JSX/TSX,那么这边可以写个收集 Tag 和 props 的 babel plugin,在 babel plugin 里面去遍历 AST,收集 Tag 和 props。
假如我们有一个 .vue 文件:
会生成下面的模板:
可以看到,从 $_TPL 的 root 节点出发,可以根据每个 item.type 来去选择下面生成的每个模板,每个模板里面又有循环,这样就可以结合VNode 无限的递归的渲染。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有