Weex渲染原理

整体架构:

JSFrameWork:

Weex 表面上是一个客户端技术,但实际上它串联起了从本地开发环境到云端部署和分发的整个链路。

npm run pack:androidadb: Android Debug Bridge

虚拟DOM:

开发者首先可以在本地像撰写 web 页面一样撰写一个 app 的页面,然后编译成一段 JavaScript 代码,形成 Weex 的一个 JS bundle;

在云端,开发者可以把生成的 JS bundle 部署上去,然后通过网络请求或预下发的方式传递到用户的移动应用客户端;

在移动应用客户端里,WeexSDK 会准备好一个 JavaScript 引擎,并且在用户打开一个 Weex 页面时执行相应的 JS bundle,并在执行过程中产生各种命令发送到 native 端进行的界面渲染或数据存储、网络通信、调用设备功能、用户交互响应等移动应用的场景实践;

同时,如果用户没有安装移动应用,他仍然可以在浏览器里打开一个相同的 web 页面,这个页面是使用相同的页面源代码,通过浏览器里的 JavaScript 引擎运行起来的。

在 Weex 的架构中,可以简略的分成三层:【DSL】->【JS Framework】->【原生渲染引擎】

其中 DSL (Domain Specific Language) 指的是 Weex 里支持的上层前端框架,即 Vue 和 Rax。原生渲染引擎就是在 Weex 支持的平台上(Android 或 iOS)绘制原生 UI 的引擎。JS Framework 是桥接并适配 DSL 和原生渲染引擎的一层。

常规组件的渲染过程可以分为如下这几个步骤:

  1. 创建前端组件
  2. 构建 Virtual DOM
  3. 生成“真实” DOM
  4. 发送渲染指令
  5. 绘制原生 UI

可以用下面这一张图来概括:

图中的 JSFM 为 JS Framework 的简写。


Weex 会把一个页面的源代码全部编译打包成一个 JS bundle,在浏览器中,我们需要把这个 JS bundle 作为一段<script>载入网页,在客户端里,我们把这段 JS bundle 载入本地,并通过 WeexSDK 直接执行。


云端部署和分发(优化)

Weex 的 JS bundle 可以作为 web 开发中的一段静态资源进行部署和下发。

几乎可以复用 HTML5 所有的工程体系和最佳实践。

比如在本地开发环境通过部署工具

  • 将 JS bundle 部署到 CDN、

  • 通过 CMS 或搭建平台把业务数据和模块化的前端组件自动化拼接生成 JS bundle、

  • 通过服务端 JS bundle 的流量和日志统计页面的访问情况、

  • 通过 AppCache 或类似的方式对 JS bundle 在客户端进行缓存或预加载以降低网络通信的成本等。

客户端 JavaScript 引擎

编写好的Weex页面(Vue),通过 weex-loader 来生成 JS bundle (通过webpack打包文件内头部:// { "framework": "Vue" } 来决定用哪种语言来执行 vue or rax?)。

weex-loader 会把入口文件(index.js),应用到的组件,按照:样式,Script,template,图片分别module.exports,template里的内置组件(div,image,waterfall, refresh...)会输出成类似下边的【客户端渲染层】

这一步,只是让客户端的JS引擎来识别执行的。还需要交给客户端的渲染层来绘画客户端的DOM树(Activity)。

Weex 的 iOS 和 Android 客户端中都会运行一个 JavaScript 引擎,来执行 JS bundle,同时向各端的渲染层发送规范化的指令,调度客户端的渲染和其它各种能力。

我们在 iOS 下选择了 JavaScriptCore 内核,而在 Android 下选择了 UC 提供的 v8 内核。

为了让整个移动应用的资源利用得更好,我们在客户端提供的 JavaScript 引擎是单例的,

即所有 JS bundle 公用一个 JavaScript 内核实例,同时对每个 JS bundle 在运行时进行了上下文的隔离,使得每个 JS bundle 都能够高效安全的工作。

我们还把 Vue 2.0 这样的 JS Framework 做了预置,开发者不必把 JS Framework 打包在每个 JS bundle 里,从而大大减少了 JS bundle 的体积,也就进一步保障了页面打开的速度。

(注:cmd> weex debug)

客户端渲染层

Weex 目前提供了 iOS 和 Android 两个客户端的 native 渲染层。

每个端都基于 DOM 模型设计并实现了标准的界面渲染接口供 JavaScript 引擎调用。

并且结合 web 标准和 native 的特点和优势实现了一套统一的组件和模块。

模板的结构和源码里的标签结构基本上是一一对应的,包含了渲染逻辑,模板指令也编译成了静态属性,一般不需要更新

在框架内部,Weex 使用的是原生系统提供的 Widget 来渲染的。


为了将模板和声明式的渲染逻辑发送给客户端,约定了一些特殊的扩展语法,这些扩展语法目前都是放在组件的属性中的。

目前已经改造了 Vue 的编译工具,能够把 Vue 的常用模板指令编译成上面描述的这些模板语法。

如:

事件绑定

如果事件处理函数没绑定参数,则不做特殊处理,和原先的格式一致,只把事件名称的字符串发给客户端;如果绑定了参数,则用一个对象表示,如下:

组件声明

前端中的组件最终会展开成节点发送给客户端,客户端并不知道哪些节点会属于同一个组件,需要添加一些标识来声明哪些节点是属于一个前端组件的。

条件指令

在模板中,使用[[match]]作为条件指令,添加在节点的属性中,属性值是可以计算出真假值的表达式字符串。如果根据该表达式计算出来的值为 false,则不渲染该节点,也不渲染其后代节点。

循环指令

在模板中,使用[[repeat]]作为循环指令,包含了三个字段,添加在节点的属性中。

一次性渲染指令

如果模板中包含v-once指令,则会在节点的属性中添加[[once]],表示该节点及其后代节点只会渲染一次,数据改变时也不会更新。

渲染过程

先创建 Virtual component Template, vue的编译工具把weex的vue页面,转化成 上边语法的模板,和数据,把这些发送给客户端来native渲染。

在渲染的过程中,可能遇到子组件,以当前节点和后代节点为一个组件来渲染。

浏览器渲染

通过 node_modules/vue/dist/vue.runtime.min.js 和 node_modules/weex-vue-render/dist/index.min.js 来实现H5端打包的业务代码js文件的渲染。

Weex的使用

weex-toolkit 是官方提供的一个脚手架命令行工具,你可以使用它进行 Weex 项目的创建调试以及打包等功能。

安装:Playground App 来通过扫码查看Weex页面效果,此app要注意版本(关于),部分weex功能和sdk版本有关。

快速上手的例子https://hanks10100.github.io/weex-vue-examples/

EMAS-Weex-IDE:EMAS 是一个面向企业的移动研发平台,基于阿里巴巴移动互联网近十年技术积累打造而成,目前已服务于阿里巴巴上百款移动应用,它包含基础架构、移动 DevOps、工程理念三大能力,并支持两种研发模式(Native+跨平台),四大移动应用生命周期职能域覆盖(研发、测试、运维、运营),五类场景解决方案输出(持续交付、跨平台、组件化、泛质量管理、网络统一接入)。

Weex 环境中没有 DOM、BOM,H5的标签请忘记。

因此你不能用 document, window, screen, history, location, navigator等。

但是,这些都有内置的模块,可以使用,也可以扩展模块来达到。

  • 检测原生 module: var xxx = require('@weex-module/xxx') 或者 weex.supports('@module/xxx')

  • 检测原生 component: var xxx = require('@weex-component/xxx') 或者 weex.supports('@component/xxx') 或者 xxx.method 方法是否存在。

  • <image :src="require('./img/gotop.png')" class="goto-top-img"></image>

  • 每个weex页面,都有一个 weex 变量, weex.config 包括了,所有的环境信息,比如:bundleUrl(当前页面 js bundle 的 URL 地址),env 环境变量, weex.config.env == WXEnvironment 有platform(“Android”, “iOS” or “Web”.)、weexVersion、appName、appVersion、osName(iOS or Android)、osVersion、deviceModel(iPhone X 环境下,weex.config.env.deviceModel 将返回 iPhone X 的特有标识 'iPhone10,3 or iPhone10,6')、deviceWidth、deviceHeight

  • const modal = weex.requireModule('modal')

  • 内置模块: dom 可以实现跳转到某个元素上, 通过 weex.requireModule('dom').scrollToElement(ref, options)

  • 内置模块:clipboard 从系统的粘贴板获取内容或者设置内容。 getString(), setString(..)

  • 内置模块: navigator 可以 push, pop 来跳转和返回操作。 返回上一页: navigator.pop({}, e=>{});

  • 内置模块: picker 可以日期选择、时间选择, H5端,需要单独引入: weex-picker组件

  • 内置模块: storage 实现本地存储, 浏览器是5M限制,客户端,没有限制大小。

  • 内置模块: stream 实现接口的调用。 stream.fetch({url: '', body: form}, function(res){}); method:POST 时,let form = new FormData(); form.append( 'body', JSON.stringify({"keyProms":"saleJdXMuG7831X","templetId":"4202731","provinceId":"","cityId":"","isFilter":"N","isHybrid":"1"}))。可以实现 form data 的方式传递, 否则,参数都是 Request Payload 方式的。

  • 内置模块: webSocket 和一个服务器之间打开一个的交互式通信会话成为可能,实现聊天。 创建 WebSockets,并连接服务器。 使用BroadcastChannel是可以实现跨页面通信的。

  • 内置模块: webview webview模块提供了一系列的<web>组件操作接口,例如goBackgoForward、和reload。一般与<web>组件一起使用。 有别于:navigator

  • 内置组件: ------------------------------------------------------------

  • 实现跳转的 <a> 。容器 <div> 。 显示图片 <image> 路径不支持 base64的图。

  • 输入<input>。<textarea> 文本框。<text> 最小组件,所有的文本,必须这个包裹。

  • 列表用<list>配合<cell>,<recycle-list>配合 <cell-solt> 更高效的列表,<scroller> 滚动的容器,列表都能用 <loading> <refresh> <indicator>来实现状态的提示,<waterfall> 瀑布流的容器,可以一行并排2个

  • <slider> 轮播图。 <switch> 开关切换。<video> 视频。 <web> 内嵌页面(https内的图片也需要https的,否则不显示图),可以通过内置模块,webview 来控制它的导航(前进,后退...)。

    查看Weex SDK 实现方法: https://github.com/apache/incubator-weex/tree/master/android/sdk/src/main/java/com/taobao/weex/ui/component

  • Weex 在样式方面的介绍

  • 支持盒模型,margin, padding, border,但是都要拆开写(都不能组合写),如: margin-top: 10px; margin-bottom: 10;

  • 像素大小,一定要写单位: px,缺少px,可能造成客户端渲染不正常。

  • overflow:hidden 在android上是默认行为,不需要写。定义容器高度(div, a, cell, refresh, loading),对里边的text做剪切。text-overflow: ellipsis; lines:2; 通过这些可以做溢出处理。 目前 Android 暂不支持设置overflow: visible

  • 布局只支持:Flexbox。 Flexbox 包含 flex 容器(定义row,column及对齐方式等)和 flex 成员项(flex: 1)。 不需要手动为元素添加display: flex;属性。

  • Weex 支持position定位,用法与 CSS position 类似。为元素设置position后,可通过toprightbottomleft四个属性设置元素坐标。

  • Weex 目前不支持 z-index 设置元素层级关系,但靠后的元素层级更高,因此,对于层级高的元素,可将其排列在后面。

  • transform(旋转,缩放,倾斜,移动),transition (v0.16.0+) 动画效果,透明,显隐,过渡,快慢。 这2个,结合 内置组件animation 来实现动画效果的执行。

  • Weex 支持四种伪类active,focus,disabled,enabled所有组件都支持active, 但只有input组件和textarea组件支持focus,enabled,disabled

  • 支持线性渐变,background-image: linear-gradient(totop,#a80077,#66ff00); 不支持径向渐变。 仅IOS支持box-shadow阴影

  • 颜色值:尽量用十六进制表示,别简写 #fff, 可以设置 opacity 透明度(0~1)

  • Weex 不支持 百分比(%)的写法。

  • 尽量都用 class 来绑定样式, 元素上style,会有性能问题和兼容问题(浏览器和客户端表现不一致的情况)

  • weex上的屏幕宽度,默认: 750px 可以通过内置模块 weex.requireModule('meta').setViewport({width: 640px, height: 800px}); 当前页面中的所有组件都会以 640px 作为满屏宽度。

  • <style>标签内,你可以写 CSS 来描述一个组件的样式,需要注意的是,这些样式在 Weex 里只能作用于当前组件。(强制scoped)。

Weex在事件方面

  • 支持: click (@click, input、switch内置组件不支持click,请用:input 或者 chang事件代替), longpress (长按触发)
  • 支持: appear,disappear,表示,某个组件出现在屏幕可视区域时或者不在可视区域时,触发的动作。可以获得,绑定的组件对象,和 屏幕滚动的方向
  • 支持:page事件,与组件的appeardisappear事件不同的是,viewappearviewdisappear事件关注的是整个页面的状态,所以它们必须绑定到页面的根元素上

  • 支持:事件冒泡。 <div class="root" @click="rootClick" bubble="true"> 为了兼容之前的版本,Weex 默认不会开启事件冒泡机制。需要在根元素的属性上,添加bubble="true"来开启冒泡机制。否则,将不会向上传播事件,保持与之前版本的效果相同。通过:e.stopPropagation() 来阻止事件冒泡。

  • 支持: 手势。 目前,仅支持以下四种手势类型:touch, pan, swipe(将会在用户在屏幕上滑动时触发,一次连续的滑动只会触发一次。可以得到滑动方向(上下左右).), longpresspan手势也会返回触摸点在触摸面的移动信息,有点类似于touch手势。但是pan手势只会采样收集部分事件信息因此比touch事件要快得多,当然精准性差于touch滚动元素(内置组件:list, scroller, webview)上监听手势,请慎用。

  • 内置模块 globalEvent 用于监听持久性事件,例如定位信息(geolocation陀螺仪(deviceorientation等的变化。提供2个方法: addEventListener 和 removeEventListener

  • 参考资料:

https://weex.apache.org/cn/guide/

https://github.com/Hanks10100/weex-native-directive/blob/master/Design.md

https://github.com/Hanks10100/weex-native-directive/blob/master/Implementation.md

https://hanks10100.github.io/weex-vue-examples/

https://weex.apache.org/cn/resources.html

https://blog.csdn.net/smallspot/article/details/53330667

results matching ""

    No results matching ""