探索Vue小程序框架的底层原理

最近晚上有时间复盘之前研究小程序框架的相关内容,总结文章记录一下。

本篇文章主要介绍百度19年开源的Mars小程序开发框架,和Taro、mpvue、uniapp类似,都是编译型小程序框架,都是通过将 Vue 或 React 源码直接编译为小程序源码,实现小程序快速开发。我们来介绍一下其设计思路与原理。

Mars是什么?

Mars 是由 Vue 驱动的多端开发框架,其语法规范完全遵循 Vue,支持一套代码同时运行到百度小程序、微信小程序以及 H5 Web 端。Mars 诞生于搜索垂类产品对于小程序和 H5 Web 端相同的产品业务需求的场景下。从框架设计研发之初,就定位于解决小程序以及 H5 Web 端的复用和同构开发能力。

设计思路

Mars 框架的设计思路是将跨多端的应用拆分为逻辑层和视图层,逻辑层采用同一套核心运行时进行数据驱动以及生命周期管理,视图层使用同一套模板语法,经过编译转换为特定平台的视图语言。

考虑到学习成本、生态完善程度以及在多端上的扩展性、业务场景等原因,我们选择了 Vue 技术栈,采用 Vue 单文件组件和模板语法来书写组件代码,引入标准基础组件和 API 规范和标准生命周期规范。

在此开发规范之上,基于 Vue 的模板语法和基础组件来构建视图层,基于 Vue 数据驱动及标准生命周期规范来构建逻辑层,实现多端运行。框架总体原理图如下:

image.png

我们分别从模板、逻辑和数据来聊聊是如何编译的。

模板

我们先看一下Vue模板和小程序模板是如何书写的:

Vue模版如下:

<!--index.wxml-->
<template class="container"><view class="userinfo"><button v-if="!hasUserInfo&&canIUse" open-type="getUserInfo">获取头像昵称</button><block v-else>  <image @tap="bindViewTap" class="userinfo-avatar" src=""/><text class="userinfo-nickname">{{userInfo.nickName}}</text></block></view><view class="usermotto"><text class="user-motto">{{motto}}</text></view>
</template>

小程序的模版内容如下:

<!--index.wxml-->
<view class="container"><view class="userinfo"><button wx:if="{{!hasUserInfo&&canIUse}}" open-type="getUserInfo">获取头像昵称</button><block wx:else>  <image bindtap="bindViewTap" class="userinfo-avatar" src=""/><text class="userinfo-nickname">{{userInfo.nickName}}</text></block></view><view class="usermotto"><text class="user-motto">{{motto}}</text></view>
</view>

如果我们对比小程序和Vue模版,会发现他们与html语法是十分相似的。区别只在于标签上属性值的写法,相互之间通过编译是可以转化的。我们可以在编译阶段由Vue模版编译到小程序模版。

逻辑

我们先看一下小程序的逻辑和Vue的逻辑部分:

Vue逻辑如下:

<script>export default{data(){},methods:{bindViewTap(){},getUserInfo(){}},mounted(){}}
</script>

小程序的逻辑如下:

Page({data:{},bindViewTap: function(){},onLoad: function(){},getUserInfo: function(){}
})

逻辑部分,小程序与Vue在书写方式上有很大差异,他们的逻辑代码在各自的运行时中执行。并且逻辑部分用户书写的灵活度是很大的,没有办法通过编译将Vue的逻辑编译成小程序的逻辑去执行。

那该怎么办呢,我们不如换一种思路。Vue运行时和Vue组件的逻辑在生产中都是以JS代码执行的,在小程序提供的环境中是可以执行的。我们可以让Vue运行时也可以在小程序中执行,这样开发者编写的Vue逻辑代码也可以在小程序中执行了。

数据

数据部分是最简单的,因为数据是以JS对象的形式存在的,在小程序和Vue中是相同的。

原理

通过对视图、逻辑和数据这三个部分的分析,我们可以使用以下思路来使用Vue开发小程序。

首先将Vue template部分编译成小程序的模版,之后在小程序逻辑部分运行整个Vue的运行时,以及开发者编写的逻辑代码。最后Vue数据发生变化时同步给小程序,触发视图刷新。

image.png
我们需要在编译阶段产出 .wxml、.css、.js以及.json文件,在template部分需要将v-bind等语法转换成小程序使用的格式。样式内容则可以直接提取出来作为css文件。我们会在Vue中规定一个字段作为配置,这部分配置会提取出来作为.json文件。

而对于js部分,由于我们的逻辑执行在Vue中,因此只需要用到小程序的生命周期,在生命周期中执行Vue运行时以及业务逻辑代码就可以了。

例如,Vue单文件组件内容如下:

<template><view class="home-wrap"><navigator :url="item.bookApi" v-for="(item,index) in bookList"><book :poster="item.poster"></book></navigator></view>
</template>
<script>
import Book from 'components/Book/index';
export default{config:{navigationBarTitleText: "标题"},data(){},components:{book:Book}
}
</script>
<style>.home-wrap{width:100vw;height:100vh;}
</style>

编译成小程序的组件内容如下:

<!--wxml模板内容--><view class="home-wrap"><navigator url="{{item.bookApi}}" v-for="(item,index) in bookList"><book poster="{{item.poster}}" compId="{{ (compId ? compId : '$root') + ',0' }}"></book></navigator>
</view>
 /*wxss样式内容*/.home-wrap{width:100vw;height:100vh;}
/*json配置内容*/
{"navigationBarTitleText": "标题","usingComponents":{"book":"../../components/Book/index"}
},
//js逻辑内容
import {createPage} from "../../mars-core/index"
import Book from "../../components/Book/index.vue"
Page(createPage({data(){},components:{book:Book}
}))

为了执行Vue运行时以及业务逻辑代码,我们需要在小程序中创建Vue实例,Vue在生产环境中是以JS代码来运行的。因此我们可以直接将Vue引入,然后在小程序onLoad阶段new一个Vue实例出来。

import Vue from 'vue'Page({onLoad(){const vm = new Vue(options)this.$vue = vm}
})

但是要注意,Vue正常是要执行在浏览器中的,在执行时会进行DOM操作完成页面渲染,在小程序中我们需要将Vue进行DOM操作的部分删掉。做到这里模版已经有了,样式也有了,创建了Vue实例后逻辑也可以执行了,但到目前为止,小程序与Vue也没有真正联系上。

通过之前的分析我们了解到,小程序与Vue之间是通过数据来联系的,Vue中执行逻辑,修改数据,将数据变化同步给小程序,触发试图更新。因此,我们现在要做的就是在每次Vue中更新视图时,把数据修改同步给小程序,那么如何知道Vue中的逻辑执行造成了视图刷新了呢?

我们可以使用Vue的updated钩子函数。

const vueMixin = {updated(){setData(vm,this)}
}

updated钩子函数会在数据发生变化导致视图刷新后触发。我们可以在其中调用小程序的setData方法,来将变化后的数据同步给小程序,现在我们在Vue和小程序之间建立了联系。但这个联系还是单向的,Vue的数据变化可以修改小程序的视图。但小程序中用户的操作还不能传递给Vue进行处理。用户的操作体现在tap等事件中,由于我们所有的逻辑都在Vue中,因此需要让Vue接管小程序的事件处理。

我们可以在小程序的模版中去设置一个代理函数handleProxy,在这个事件代理函数中,调用Vue实例中的事件处理函数,触发开发者编写的业务处理逻辑。这样用户的操作通过事件代理传递给Vue进行处理,Vue处理过程中会修改数据,触发VirtualDom的更新,VirtualDom更新后会触发updated钩子函数,我们在updated钩子函数中将数据变化同步给小程序,使得小程序视图更新,完成了整个用户操作响应流程。

现在我们已经完成了Vue与小程序结合的整体结构,视图绘制发生在小程序中,业务逻辑运行在Vue中,小程序与Vue用事件和数据来进行通信。

组件机制原理也是一样的,视图依旧由小程序组件来绘制,业务逻辑运行在Vue组件中,小程序组件与Vue组件通过事件和数据来进行通信。

但是这么做的前提是我们需要将小程序组件与Vue组件关联起来,在我们创建Vue实例时有两种选择,一种是我们只在小程序根组件也就是Page中去创建Vue实例,Vue会继续创建组件实例。

image.png

在这种情况下小程序组件和Vue组件的创建分别是同时进行的,那么我们就需要将小程序组件与Vue组件之间进行关联匹配,否则他们之间的通信也就无从谈起了。

那么如何匹配呢?我们可以给每个组件都标记一个唯一的ID,然后通过ID来进行匹配。标记的方法就是从根组件开始,将根组件标记为 r o o t ,那么它的子组件就是 root,那么它的子组件就是 root,那么它的子组件就是root.0,$root.1等,不同层级间使用.来分割,其中列表循环特殊对待,我们使用横线来标记循环项。

例如root.1中有一个循环列表,这个循环列表中渲染了一个组件这个组件自身ID位root.1.0,然后循环产生的第一个子组件就是root.1.0-0,第二个就是root.1.0-1,这样我们通过ID给每个组件增加了标记,将相同ID的小程序组件与Vue组件匹配在一起。

另一种是我们去掉Vue创建组件实例的逻辑,自己在每个小程序组件创建时new一个Vue实例,但如果这么做,我们需要自己维护Vue各个实例间的父子关系。

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/257365.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库字段名和sql关键字冲突报错解决方法

1、修改实体类字段映射。注解里加反引号 2、sql字段上加反引号 3、问题解决

MySQL_4.mysql数据库的安装(超详细——保姆级)

1.mysql 单实例、多实例安装 端口&#xff1a;&#xff08;3306、3307&#xff09; 环境&#xff1a;win11/win10 , mysql_5.7.30 2.安装Windows VC 、NET4.0 等系统组件 下载链接百度网盘: 链接&#xff1a;https://pan.baidu.com/s/1goIbaJ6YC-DzmBbVDyOolg 提取码&…

IPTABLES(一)

文章目录 1. iptables基本介绍1.1 什么是防火墙1.2 防火墙种类1.3 iptables介绍1.4 包过滤防火墙1.5 包过滤防火墙如何实现 2. iptables链的概念2.1 什么是链2.2 iptables有哪些链 3. iptables表的概念3.1 什么是表3.2 表的功能3.3 表与链的关系 4. iptables规则管理4.1 什么是…

将单体应用程序迁移到微服务

多年来&#xff0c;我处理过多个单体应用&#xff0c;并将其中一些迁移到了微服务架构。我打算写下我所学到的东西以及我从经验中用到的策略&#xff0c;以实现成功的迁移。在这篇文章中&#xff0c;我将以AWS为例&#xff0c;但基本原则保持不变&#xff0c;可用于任何类型的基…

vue2+datav可视化数据大屏(2)

接上一节所说 我们已经讲骨架搭好 这节我们讲述的如何在vue2中使用mock数据和封装axios 1&#xff0c;项目中使用moke &#x1f4d3;什么是mock&#xff1f;&#xff0c;mock就是假数据&#xff0c;除了数据是假的&#xff0c;其他内容都和正常工作中后端开发的接口都是一致的…

JavaScript实战:制作一个待办事项列表应用

JavaScript实战&#xff1a;制作一个待办事项列表应用 引言 在本教程中&#xff0c;我们将一步步创建一个简单的待办事项列表应用&#xff0c;这不仅会帮助你学习基本的JavaScript编程概念&#xff0c;还会教会你如何处理事件以及操作DOM。这个项目是面向初学者的&#xff0c…

Zookeeper单机模式搭建

1、下载 ​wget https://dlcdn.apache.org/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz 2、解压 tar -zxvf apache-zookeeper-3.6.3-bin.tar.gz 3、进入 apache-zookeeper-3.6.3-bin目录下&#xff0c;创建data cd apache-zookeeper-3.6.3-bin mkdir da…

makefile中选项说明

-C gcc的-c选项表示只编译不链接。不带-c选项则默认既编译又链接。 CFLAGS编译参数 LDFLAGS链接参数 指定LIBS是要链接的库的目录。LDFLAGS告诉链接器从哪里寻找库文件。 LDFLAGS指定-L虽然能让链接器找到库进行链接&#xff0c;但是运行时链接器却找不到这个库&#xff0c;…

Docker安装postgres最新版

1. postgres数据库 PostgreSQL是一种开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是一种高度可扩展的、可靠的、功能丰富的数据库系统。以下是关于PostgreSQL的一些介绍&#xff1a; 开源性&#xff1a;PostgreSQL是一个开源项目&#xff0c;可以…

嵌入式系统

嵌入式系统 目前国内一个普遍认同的嵌入式系统定义是&#xff1a;以应用为中心、以计算机技术为基础&#xff0c;软件硬件可裁剪&#xff0c;适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。&#xff08;引用自《嵌入式系统设计师教程》&#xff09; …

MangoDB数据可updata报错

报错详情 报错原因 语法错误&#xff0c;我们调整语法即可 update&#xff08;{要修改的行}&#xff0c;{$set{要修改的字段}}&#xff09;

【Java基础系列】Cron表达式入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…