We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
刚搭建了一个博客,咋都得写上几篇文章,不然不就白搭了。
一开始打算用 hexo + gitalk + github 搭建一个,但是人太懒,总想一次完事,以后更新就写一篇 .md 文章就可以了,不想弄其他流程了,然后就用了 vue + github-issuse-api + gitalk + github 搭建了一个一劳永逸的办法,除非 github 挂了。
官方介绍 是小程序【最早(wepy你已经很成熟了)】 的框架之一,是一款让小程序支持 【组件化开发(现在小程序已经支持npm构建,好像没啥优势)】 的框架,通过预编译的手段让开发者可以选择自己 【喜欢的开发风格(类 vue 语法,数据劫持,自动 setData)】 去开发小程序。框架的细节优化,Promise,【Async Functions(原生不支持)】的引入都是为了能让开发小程序项目变得更加简单,高效
- 优点 - vue 语法,更好的开发体验 - 更好的组件化 - 更多的组件库 - 支持更多 ECMAscript 语法 - 缺点 - 官方维护不太积极,遇到问题解决太慢 - 引入了额外的代码,增加了代码体积
- 研究源码版本 2.0.0-alpha.8 - wepy 核心代码是 cli 和 core - wepy-cli 是文件转换打包的处理 - core 是对数据绑定生命周期注入的处理
// core/weapp/apis/index.js import { app, page, component } from '../native/index'; export function initGlobalAPI (wepy) { wepy.app = app; // return App({}) wepy.page = page; // return Page({}) wepy.component = component; // return Component({}) return wepy; }
写过 wepy2.0 的就知道,通过 wepy.page(), wepy.component(), 注入页面和组件,以及在app.wpy中的 wepy.app() 方法 ,通过这三个方法,分别会返回 App() Page() Component(),写过原生到小伙伴是不是很熟悉这三个 函数,分别是实现组册小程序,注册页面和组件,这样就和原生关联起来了
拿 app 为例, 首先这个函数做了什么?app 函数里运行 patchAppLifecycle 函数 并传入小程序运行环境 appConfig 中的对象【相当于 APP({}) 函数中的对象】,然后将 所有生命周期绑定上去,每次原生环境运行,触发原生生命周期,每个生命周期都会触发一个回调函数,在执行 .wey 文件中存在的生命周期函数逻辑,这样,小程序的生命周期和你页面的生命周期进行了关联
// core/weapp/native/app.js export function app (option, rel) { let appConfig = {}; patchAppLifecycle(appConfig, option, rel); // 注册和初始化生命周期 return App(appConfig); // 这里最终运行于小程序中 appConfig 就是小程序js中的逻辑 } // patchAppLifecycle 函数 // core/weapp/init/lifecycle export function patchAppLifecycle (appConfig, options, rel = {}) { appConfig.onLaunch = function (...args) { let vm = new WepyApp(); // 生命周期回调,触发页面生命周期函数 return callUserMethod(vm, vm.$options, 'onLaunch', args); }; // 相当于 App({onLaunch: function() {}}) // 获取生命周期列表 let lifecycle = getLifecycycle(WEAPP_APP_LIFECYCLE, rel, 'app'); // 循环绑定生命周期 lifecycle.forEach(k => { appConfig[k] = function (...args) { return callUserMethod(app, app.$options, k, args); }; }); };
如果你了解过 vue 的数据绑定那这个实现原理也和 vue 一样 (虚!!我怀疑是抄的,连函数名都一样),也是实现了一个观察者模式,只是,vue 做的更新处理是 patch 函数 diff 虚拟 dom 实现更新 web,而,wepy做调是调用 setData 更新数据,话不多说,上代码。
// core/weapp/init/lifecycle export function patchLifecycle (output, options, rel, isComponent) { // output 小程序的运行环境 const initLifecycle = function (...args) { let vm = new initClass(); // 将小程序 this 绑定到 vm.$wx 上去 vm.$wx = this; // 初始化数据,进行数据绑定,进行绑定对数据只是 data 中的数据 initData(vm, output.data, isComponent); // 进行依赖收集,做 setData initRender(vm, Object.keys(vm._data).concat(Object.keys(vm._props)).concat(Object.keys(vm._computedWatchers || {}))); return callUserMethod(vm, vm.$options, 'created', args); }; // 绑定到小程序到生命周期中去,做点事 // 相当于 Page({created: initLifecycle(){}}) output.created = initLifecycle; };
来看看 initData 做了啥, 对 data 进行了处理,代理到 _data 属性上去,进行观察
export function initData (vm, data) { vm._data = _data; Object.keys(_data).forEach(key => {proxy(vm, '_data', key)}); observe({ vm: vm, key: '', value: _data, parent: '', root: true }); }
observe 函数做了啥
// core/weapp/observer/index.js export function observe ({vm, key, value, parent, root}) { // 判断是否为观察者 __ob__ 属性定义 if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__ } // 观察数据 ob = new Observer({vm: vm, key: key, value: value, parent}); return ob } class Observer { // 如果是数组,则做特殊处理,因为数组 push, pop 等不能劫持,所以需要特殊处理 if (Array.isArray(value)) { const augment = hasProto ? protoAugment : copyAugment augment(value, arrayMethods, arrayKeys) this.observeArray(key, value); } else { // 否则劫持数据 this.walk(key, value); } } walk (key, obj) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive({ vm: this.vm, obj: obj, key: keys[i], value: obj[keys[i]], parent: obj }); } } defineReactive () { Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { const val = getter ? getter.call(obj) : value // 依赖收集 if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() if (Array.isArray(val)) { dependArray(val) } } } return val }, set: function reactiveSetter (newVal) { const val = getter ? getter.call(obj) : value // 更新数据 value = newVal // 通知数据更新 dep.notify(); } }) }
如果是数组需要做特殊处理,数据,push,pop等方式改变等数据不能被劫持,如果不是,就做数据劫持 getter setter,数据劫持的初始化已经做完了,现在在来看如进行等依赖收集,回到 initRender() 上了,进行依赖收集,就得触发一次数据到 getter, initRender 就是干这个的,watch 观察每个页面实例,触发一次 data getter 进行依赖收集,每次 setter 到时候就会触发这个函数 setData
// core/weapp/init/render.js export function initRender (vm, keys) { return new Watcher(vm, function () { // 会触发数据到 getter 进行依赖收集 Object.keys(keys).forEach(key => clone(vm[key])) // 调用 setData 进行数据更新,vm.$wx 在页面 created 钩子到时候进行绑定,写在了前面,是小程序中的 this vm.$wx.setData(dirty, renderFlushCallbacks) } }, function () { }, null, true); };
可以看到最后编译出来就是执行最开始导出的三个函数,对应到不同的小程序页中去
// app.js // vendor.js 为编译后的核心代码,相当于,导出的 wepy var _core = _interopRequireDefault(require('vendor.js')(1)); // 调用 app 函数,return App({}) 完成对小程序的注册 _core["default"].app({}, {a: 1})
// page.js // vendor.js 为编译后的核心代码,相当于,导出的 wepy var _core = _interopRequireDefault(require('../vendor.js')(1)); // 调用 page 函数,return Page({}) 完成对小程序页面的注册 _core["default"].page({}, {});
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
刚搭建了一个博客,咋都得写上几篇文章,不然不就白搭了。
关于 博客
一开始打算用 hexo + gitalk + github 搭建一个,但是人太懒,总想一次完事,以后更新就写一篇 .md 文章就可以了,不想弄其他流程了,然后就用了 vue + github-issuse-api + gitalk + github 搭建了一个一劳永逸的办法,除非 github 挂了。
关于 wepy
官方介绍
是小程序【最早(wepy你已经很成熟了)】 的框架之一,是一款让小程序支持 【组件化开发(现在小程序已经支持npm构建,好像没啥优势)】 的框架,通过预编译的手段让开发者可以选择自己 【喜欢的开发风格(类 vue 语法,数据劫持,自动 setData)】 去开发小程序。框架的细节优化,Promise,【Async Functions(原生不支持)】的引入都是为了能让开发小程序项目变得更加简单,高效
优缺点
代码库
core 源码探索
wepy 是怎么编译之后运行到小程序中去的?
写过 wepy2.0 的就知道,通过 wepy.page(), wepy.component(), 注入页面和组件,以及在app.wpy中的 wepy.app() 方法 ,通过这三个方法,分别会返回 App() Page() Component(),写过原生到小伙伴是不是很熟悉这三个 函数,分别是实现组册小程序,注册页面和组件,这样就和原生关联起来了
wepy 怎样实现生命周期绑定关联的了?
拿 app 为例, 首先这个函数做了什么?app 函数里运行 patchAppLifecycle 函数 并传入小程序运行环境 appConfig 中的对象【相当于 APP({}) 函数中的对象】,然后将 所有生命周期绑定上去,每次原生环境运行,触发原生生命周期,每个生命周期都会触发一个回调函数,在执行 .wey 文件中存在的生命周期函数逻辑,这样,小程序的生命周期和你页面的生命周期进行了关联
数据绑定
如果你了解过 vue 的数据绑定那这个实现原理也和 vue 一样 (虚!!我怀疑是抄的,连函数名都一样),也是实现了一个观察者模式,只是,vue 做的更新处理是 patch 函数 diff 虚拟 dom 实现更新 web,而,wepy做调是调用 setData 更新数据,话不多说,上代码。
来看看 initData 做了啥, 对 data 进行了处理,代理到 _data 属性上去,进行观察
observe 函数做了啥
如果是数组需要做特殊处理,数据,push,pop等方式改变等数据不能被劫持,如果不是,就做数据劫持 getter setter,数据劫持的初始化已经做完了,现在在来看如进行等依赖收集,回到 initRender() 上了,进行依赖收集,就得触发一次数据到 getter, initRender 就是干这个的,watch 观察每个页面实例,触发一次 data getter 进行依赖收集,每次 setter 到时候就会触发这个函数 setData
编译结果
可以看到最后编译出来就是执行最开始导出的三个函数,对应到不同的小程序页中去
The text was updated successfully, but these errors were encountered: