提交 50ddc172 编写于 作者: fxy060608's avatar fxy060608

build uni runtime

上级 aa7cc9ae
...@@ -44,8 +44,6 @@ const SYNC_API_RE = /requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Syn ...@@ -44,8 +44,6 @@ const SYNC_API_RE = /requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Syn
const CONTEXT_API_RE = /^create|Manager$/; const CONTEXT_API_RE = /^create|Manager$/;
const TASK_APIS = ['request', 'downloadFile', 'uploadFile', 'connectSocket'];
const CALLBACK_API_RE = /^on/; const CALLBACK_API_RE = /^on/;
function isContextApi (name) { function isContextApi (name) {
...@@ -59,10 +57,6 @@ function isCallbackApi (name) { ...@@ -59,10 +57,6 @@ function isCallbackApi (name) {
return CALLBACK_API_RE.test(name) return CALLBACK_API_RE.test(name)
} }
function isTaskApi (name) {
return TASK_APIS.indexOf(name) !== -1
}
function handlePromise (promise) { function handlePromise (promise) {
return promise.then(data => { return promise.then(data => {
return [null, data] return [null, data]
...@@ -74,8 +68,7 @@ function shouldPromise (name) { ...@@ -74,8 +68,7 @@ function shouldPromise (name) {
if ( if (
isContextApi(name) || isContextApi(name) ||
isSyncApi(name) || isSyncApi(name) ||
isCallbackApi(name) || isCallbackApi(name)
isTaskApi(name)
) { ) {
return false return false
} }
...@@ -268,8 +261,8 @@ var api = /*#__PURE__*/Object.freeze({ ...@@ -268,8 +261,8 @@ var api = /*#__PURE__*/Object.freeze({
requireNativePlugin: requireNativePlugin requireNativePlugin: requireNativePlugin
}); });
const WXPage = Page; const MPPage = Page;
const WXComponent = Component; const MPComponent = Component;
const customizeRE = /:/g; const customizeRE = /:/g;
...@@ -278,12 +271,10 @@ const customize = cached((str) => { ...@@ -278,12 +271,10 @@ const customize = cached((str) => {
}); });
function initTriggerEvent (mpInstance) { function initTriggerEvent (mpInstance) {
if (wx.canIUse('nextTick')) { // 微信旧版本基础库不支持重写triggerEvent const oldTriggerEvent = mpInstance.triggerEvent;
const oldTriggerEvent = mpInstance.triggerEvent; mpInstance.triggerEvent = function (event, ...args) {
mpInstance.triggerEvent = function (event, ...args) { return oldTriggerEvent.apply(mpInstance, [customize(event), ...args])
return oldTriggerEvent.apply(mpInstance, [customize(event), ...args]) };
};
}
} }
Page = function (options = {}) { Page = function (options = {}) {
...@@ -299,7 +290,7 @@ Page = function (options = {}) { ...@@ -299,7 +290,7 @@ Page = function (options = {}) {
return oldHook.apply(this, args) return oldHook.apply(this, args)
}; };
} }
return WXPage(options) return MPPage(options)
}; };
const behavior = Behavior({ const behavior = Behavior({
...@@ -310,10 +301,10 @@ const behavior = Behavior({ ...@@ -310,10 +301,10 @@ const behavior = Behavior({
Component = function (options = {}) { Component = function (options = {}) {
(options.behaviors || (options.behaviors = [])).unshift(behavior); (options.behaviors || (options.behaviors = [])).unshift(behavior);
return WXComponent(options) return MPComponent(options)
}; };
const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__']; const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__', '__webviewId__'];
function initMocks (vm) { function initMocks (vm) {
const mpInstance = vm.$mp[vm.mpType]; const mpInstance = vm.$mp[vm.mpType];
...@@ -515,7 +506,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam ...@@ -515,7 +506,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam
if (isCustomMPEvent) { if (isCustomMPEvent) {
return [event] return [event]
} }
return event.detail return event.detail.__args__ || event.detail
} }
} }
...@@ -528,7 +519,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam ...@@ -528,7 +519,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam
ret.push(event.target.value); ret.push(event.target.value);
} else { } else {
if (isCustom && !isCustomMPEvent) { if (isCustom && !isCustomMPEvent) {
ret.push(event.detail[0]); ret.push(event.detail.__args__[0]);
} else { // wxcomponent 组件或内置组件 } else { // wxcomponent 组件或内置组件
ret.push(event); ret.push(event);
} }
...@@ -600,7 +591,7 @@ function initRefs (vm) { ...@@ -600,7 +591,7 @@ function initRefs (vm) {
const mpInstance = vm.$mp[vm.mpType]; const mpInstance = vm.$mp[vm.mpType];
Object.defineProperty(vm, '$refs', { Object.defineProperty(vm, '$refs', {
get () { get () {
const $refs = Object.create(null); const $refs = {};
const components = mpInstance.selectAllComponents('.vue-ref'); const components = mpInstance.selectAllComponents('.vue-ref');
components.forEach(component => { components.forEach(component => {
const ref = component.dataset.ref; const ref = component.dataset.ref;
...@@ -620,13 +611,24 @@ function initRefs (vm) { ...@@ -620,13 +611,24 @@ function initRefs (vm) {
} }
const hooks = [ const hooks = [
'onShow',
'onHide', 'onHide',
'onError', 'onError',
'onPageNotFound', 'onPageNotFound',
'onUniNViewMessage' 'onUniNViewMessage'
]; ];
function initVm (vm) {
if (this.$vm) { // 百度竟然 onShow 在 onLaunch 之前?
return
}
this.$vm = vm;
this.$vm.$mp = {
app: this
};
}
function createApp (vm) { function createApp (vm) {
// 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin // 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin
Vue.mixin({ Vue.mixin({
...@@ -643,7 +645,9 @@ function createApp (vm) { ...@@ -643,7 +645,9 @@ function createApp (vm) {
delete this.$options.mpInstance; delete this.$options.mpInstance;
if (this.mpType !== 'app') { if (this.mpType !== 'app') {
initRefs(this); { // 头条的 selectComponent 竟然是异步的
initRefs(this);
}
initMocks(this); initMocks(this);
} }
}, },
...@@ -655,17 +659,17 @@ function createApp (vm) { ...@@ -655,17 +659,17 @@ function createApp (vm) {
const appOptions = { const appOptions = {
onLaunch (args) { onLaunch (args) {
initVm.call(this, vm);
this.$vm = vm;
this.$vm.$mp = {
app: this
};
this.$vm._isMounted = true; this.$vm._isMounted = true;
this.$vm.__call_hook('mounted'); this.$vm.__call_hook('mounted');
this.$vm.__call_hook('onLaunch', args); this.$vm.__call_hook('onLaunch', args);
},
onShow (args) {
initVm.call(this, vm);
this.$vm.__call_hook('onShow', args);
} }
}; };
...@@ -701,6 +705,16 @@ function handleLink (event) { ...@@ -701,6 +705,16 @@ function handleLink (event) {
} }
} }
function initPage$1 (pageOptions) {
initComponent$1(pageOptions);
}
function initComponent$1 (componentOptions) {
componentOptions.methods.$getAppWebview = function () {
return plus.webview.getWebviewById(`${this.__wxWebviewId__}`)
};
}
const hooks$1 = [ const hooks$1 = [
'onShow', 'onShow',
'onHide', 'onHide',
...@@ -717,6 +731,20 @@ const hooks$1 = [ ...@@ -717,6 +731,20 @@ const hooks$1 = [
'onNavigationBarSearchInputClicked' 'onNavigationBarSearchInputClicked'
]; ];
function initVm$1 (VueComponent) { // 百度的 onLoad 触发在 attached 之前
if (this.$vm) {
return
}
this.$vm = new VueComponent({
mpType: 'page',
mpInstance: this
});
this.$vm.__call_hook('created');
this.$vm.$mount();
}
function createPage (vueOptions) { function createPage (vueOptions) {
vueOptions = vueOptions.default || vueOptions; vueOptions = vueOptions.default || vueOptions;
let VueComponent; let VueComponent;
...@@ -734,14 +762,7 @@ function createPage (vueOptions) { ...@@ -734,14 +762,7 @@ function createPage (vueOptions) {
data: getData(vueOptions, Vue.prototype), data: getData(vueOptions, Vue.prototype),
lifetimes: { // 当页面作为组件时 lifetimes: { // 当页面作为组件时
attached () { attached () {
initVm$1.call(this, VueComponent);
this.$vm = new VueComponent({
mpType: 'page',
mpInstance: this
});
this.$vm.__call_hook('created');
this.$vm.$mount();
}, },
ready () { ready () {
this.$vm.__call_hook('beforeMount'); this.$vm.__call_hook('beforeMount');
...@@ -755,6 +776,7 @@ function createPage (vueOptions) { ...@@ -755,6 +776,7 @@ function createPage (vueOptions) {
}, },
methods: { // 作为页面时 methods: { // 作为页面时
onLoad (args) { onLoad (args) {
initVm$1.call(this, VueComponent);
this.$vm.$mp.query = args; // 又要兼容 mpvue this.$vm.$mp.query = args; // 又要兼容 mpvue
this.$vm.__call_hook('onLoad', args); // 开发者可能会在 onLoad 时赋值,提前到 mount 之前 this.$vm.__call_hook('onLoad', args); // 开发者可能会在 onLoad 时赋值,提前到 mount 之前
}, },
...@@ -767,41 +789,37 @@ function createPage (vueOptions) { ...@@ -767,41 +789,37 @@ function createPage (vueOptions) {
}; };
initHooks(pageOptions.methods, hooks$1); initHooks(pageOptions.methods, hooks$1);
{ initPage$1(pageOptions);
pageOptions.methods.$getAppWebview = function () {
return plus.webview.getWebviewById(`${this.__wxWebviewId__}`)
};
}
return Component(pageOptions) return Component(pageOptions)
} }
function initVueComponent (mpInstace, VueComponent, extraOptions = {}) { function initVm$2 (VueComponent) {
if (mpInstace.$vm) { if (this.$vm) {
return return
} }
const options = Object.assign({ const options = {
mpType: 'component', mpType: 'component',
mpInstance: mpInstace, mpInstance: this,
propsData: mpInstace.properties propsData: this.properties
}, extraOptions); };
// 初始化 vue 实例 // 初始化 vue 实例
mpInstace.$vm = new VueComponent(options); this.$vm = new VueComponent(options);
// 处理$slots,$scopedSlots(暂不支持动态变化$slots) // 处理$slots,$scopedSlots(暂不支持动态变化$slots)
const vueSlots = mpInstace.properties.vueSlots; const vueSlots = this.properties.vueSlots;
if (Array.isArray(vueSlots) && vueSlots.length) { if (Array.isArray(vueSlots) && vueSlots.length) {
const $slots = Object.create(null); const $slots = Object.create(null);
vueSlots.forEach(slotName => { vueSlots.forEach(slotName => {
$slots[slotName] = true; $slots[slotName] = true;
}); });
mpInstace.$vm.$scopedSlots = mpInstace.$vm.$slots = $slots; this.$vm.$scopedSlots = this.$vm.$slots = $slots;
} }
// 性能优先,mount 提前到 attached 中,保证组件首次渲染数据被合并 // 性能优先,mount 提前到 attached 中,保证组件首次渲染数据被合并
// 导致与标准 Vue 的差异,data 和 computed 中不能使用$parent,provide等组件属性 // 导致与标准 Vue 的差异,data 和 computed 中不能使用$parent,provide等组件属性
mpInstace.$vm.$mount(); this.$vm.$mount();
} }
function createComponent (vueOptions) { function createComponent (vueOptions) {
...@@ -820,10 +838,10 @@ function createComponent (vueOptions) { ...@@ -820,10 +838,10 @@ function createComponent (vueOptions) {
properties, properties,
lifetimes: { lifetimes: {
attached () { attached () {
initVueComponent(this, VueComponent); initVm$2.call(this, VueComponent);
}, },
ready () { ready () {
initVueComponent(this, VueComponent); // 目前发现部分情况小程序 attached 不触发 initVm$2.call(this, VueComponent); // 目前发现部分情况小程序 attached 不触发
triggerLink(this); // 处理 parent,children triggerLink(this); // 处理 parent,children
// 补充生命周期 // 补充生命周期
...@@ -854,6 +872,8 @@ function createComponent (vueOptions) { ...@@ -854,6 +872,8 @@ function createComponent (vueOptions) {
} }
}; };
initComponent$1(componentOptions);
return Component(componentOptions) return Component(componentOptions)
} }
......
{ {
"name": "@dcloudio/uni-app-plus", "name": "@dcloudio/uni-app-plus",
"version": "0.0.216", "version": "0.0.217",
"description": "uni-app app-plus", "description": "uni-app app-plus",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
......
此差异已折叠。
{ {
"name": "@dcloudio/uni-mp-baidu", "name": "@dcloudio/uni-mp-baidu",
"version": "0.0.812", "version": "0.0.813",
"description": "uni-app mp-baidu", "description": "uni-app mp-baidu",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
......
...@@ -19,9 +19,28 @@ function hasOwn (obj, key) { ...@@ -19,9 +19,28 @@ function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key) return hasOwnProperty.call(obj, key)
} }
function noop () {} function noop () {}
/**
* Create a cached version of a pure function.
*/
function cached (fn) {
const cache = Object.create(null);
return function cachedFn (str) {
const hit = cache[str];
return hit || (cache[str] = fn(str))
}
}
/**
* Camelize a hyphen-delimited string.
*/
const camelizeRE = /-(\w)/g;
const camelize = cached((str) => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
});
const SYNC_API_RE = /hideKeyboard|upx2px|canIUse|^create|Sync$|Manager$/; const SYNC_API_RE = /requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$/;
const CONTEXT_API_RE = /^create|Manager$/; const CONTEXT_API_RE = /^create|Manager$/;
...@@ -46,10 +65,11 @@ function handlePromise (promise) { ...@@ -46,10 +65,11 @@ function handlePromise (promise) {
} }
function shouldPromise (name) { function shouldPromise (name) {
if (isSyncApi(name)) { if (
return false isContextApi(name) ||
} isSyncApi(name) ||
if (isCallbackApi(name)) { isCallbackApi(name)
) {
return false return false
} }
return true return true
...@@ -426,7 +446,50 @@ var api = /*#__PURE__*/Object.freeze({ ...@@ -426,7 +446,50 @@ var api = /*#__PURE__*/Object.freeze({
}); });
const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__']; const MPPage = Page;
const MPComponent = Component;
const customizeRE = /:/g;
const customize = cached((str) => {
return camelize(str.replace(customizeRE, '-'))
});
function initTriggerEvent (mpInstance) {
const oldTriggerEvent = mpInstance.triggerEvent;
mpInstance.triggerEvent = function (event, ...args) {
return oldTriggerEvent.apply(mpInstance, [customize(event), ...args])
};
}
Page = function (options = {}) {
const name = 'onLoad';
const oldHook = options[name];
if (!oldHook) {
options[name] = function () {
initTriggerEvent(this);
};
} else {
options[name] = function (...args) {
initTriggerEvent(this);
return oldHook.apply(this, args)
};
}
return MPPage(options)
};
const behavior = Behavior({
created () {
initTriggerEvent(this);
}
});
Component = function (options = {}) {
(options.behaviors || (options.behaviors = [])).unshift(behavior);
return MPComponent(options)
};
const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__', '__webviewId__'];
function initMocks (vm) { function initMocks (vm) {
const mpInstance = vm.$mp[vm.mpType]; const mpInstance = vm.$mp[vm.mpType];
...@@ -437,25 +500,21 @@ function initMocks (vm) { ...@@ -437,25 +500,21 @@ function initMocks (vm) {
}); });
} }
function initHooks (mpOptions, hooks, delay = false) { function initHooks (mpOptions, hooks) {
hooks.forEach(hook => { hooks.forEach(hook => {
mpOptions[hook] = function (args) { mpOptions[hook] = function (args) {
if (delay) { return this.$vm.__call_hook(hook, args)
setTimeout(() => this.$vm.__call_hook(hook, args));
} else {
this.$vm.__call_hook(hook, args);
}
}; };
}); });
} }
function getData (vueOptions) { function getData (vueOptions, context) {
let data = vueOptions.data || {}; let data = vueOptions.data || {};
const methods = vueOptions.methods || {}; const methods = vueOptions.methods || {};
if (typeof data === 'function') { if (typeof data === 'function') {
try { try {
data = data(); data = data.call(context); // 支持 Vue.prototype 上挂的数据
} catch (e) { } catch (e) {
if (process.env.VUE_APP_DEBUG) { if (process.env.VUE_APP_DEBUG) {
console.warn('根据 Vue 的 data 函数初始化小程序 data 失败,请尽量确保 data 函数中不访问 vm 对象,否则可能影响首次数据渲染速度。', data); console.warn('根据 Vue 的 data 函数初始化小程序 data 失败,请尽量确保 data 函数中不访问 vm 对象,否则可能影响首次数据渲染速度。', data);
...@@ -469,7 +528,7 @@ function getData (vueOptions) { ...@@ -469,7 +528,7 @@ function getData (vueOptions) {
} }
Object.keys(methods).forEach(methodName => { Object.keys(methods).forEach(methodName => {
if (!hasOwn(data, methodName)) { if (context.__lifecycle_hooks__.indexOf(methodName) === -1 && !hasOwn(data, methodName)) {
data[methodName] = methods[methodName]; data[methodName] = methods[methodName];
} }
}); });
...@@ -539,24 +598,123 @@ function wrapper$1 (event) { ...@@ -539,24 +598,123 @@ function wrapper$1 (event) {
event.preventDefault = noop; event.preventDefault = noop;
event.target = event.target || {}; event.target = event.target || {};
event.detail = event.detail || {};
if (!hasOwn(event, 'detail')) {
event.detail = {};
}
// TODO 又得兼容 mpvue 的 mp 对象 // TODO 又得兼容 mpvue 的 mp 对象
event.mp = event; event.mp = event;
event.target = Object.assign({}, event.target, event.detail);
if (isPlainObject(event.detail)) {
event.target = Object.assign({}, event.target, event.detail);
}
return event return event
} }
function processEventArgs (event, args = [], isCustom) { function getExtraValue (vm, dataPathsArray) {
if (isCustom && !args.length) { // 无参数,直接传入 detail 数组 let context = vm;
return event.detail dataPathsArray.forEach(dataPathArray => {
const dataPath = dataPathArray[0];
const value = dataPathArray[2];
if (dataPath || typeof value !== 'undefined') { // ['','',index,'disable']
const propPath = dataPathArray[1];
const valuePath = dataPathArray[3];
const vFor = dataPath ? vm.__get_value(dataPath, context) : context;
if (Number.isInteger(vFor)) {
context = value;
} else if (!propPath) {
context = vFor[value];
} else {
if (Array.isArray(vFor)) {
context = vFor.find(vForItem => {
return vm.__get_value(propPath, vForItem) === value
});
} else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find(vForKey => {
return vm.__get_value(propPath, vFor[vForKey]) === value
});
} else {
console.error('v-for 暂不支持循环数据:', vFor);
}
}
if (valuePath) {
context = vm.__get_value(valuePath, context);
}
}
});
return context
}
function processEventExtra (vm, extra) {
const extraObj = {};
if (Array.isArray(extra) && extra.length) {
/**
*[
* ['data.items', 'data.id', item.data.id],
* ['metas', 'id', meta.id]
*],
*[
* ['data.items', 'data.id', item.data.id],
* ['metas', 'id', meta.id]
*],
*'test'
*/
extra.forEach((dataPath, index) => {
if (typeof dataPath === 'string') {
if (!dataPath) { // model,prop.sync
extraObj['$' + index] = vm;
} else {
extraObj['$' + index] = vm.__get_value(dataPath);
}
} else {
extraObj['$' + index] = getExtraValue(vm, dataPath);
}
});
} }
return extraObj
}
function processEventArgs (vm, event, args = [], extra = [], isCustom, methodName) {
let isCustomMPEvent = false; // wxcomponent 组件,传递原始 event 对象
if (isCustom) { // 自定义事件
isCustomMPEvent = event.currentTarget &&
event.currentTarget.dataset &&
event.currentTarget.dataset.comType === 'wx';
if (!args.length) { // 无参数,直接传入 event 或 detail 数组
if (isCustomMPEvent) {
return [event]
}
return event.detail.__args__ || event.detail
}
}
const extraObj = processEventExtra(vm, extra);
const ret = []; const ret = [];
args.forEach(arg => { args.forEach(arg => {
if (arg === '$event') { if (arg === '$event') {
ret.push(isCustom ? event.detail[0] : event); if (methodName === '__set_model' && !isCustom) { // input v-model value
ret.push(event.target.value);
} else {
if (isCustom && !isCustomMPEvent) {
ret.push(event.detail.__args__[0]);
} else { // wxcomponent 组件或内置组件
ret.push(event);
}
}
} else { } else {
ret.push(arg); if (typeof arg === 'string' && hasOwn(extraObj, arg)) {
ret.push(extraObj[arg]);
} else {
ret.push(arg);
}
} }
}); });
...@@ -588,54 +746,52 @@ function handleEvent (event) { ...@@ -588,54 +746,52 @@ function handleEvent (event) {
if (eventsArray && eventType === type) { if (eventsArray && eventType === type) {
eventsArray.forEach(eventArray => { eventsArray.forEach(eventArray => {
const handler = this.$vm[eventArray[0]]; const methodName = eventArray[0];
if (!isFn(handler)) { if (methodName) {
throw new Error(` _vm.${eventArray[0]} is not a function`) const handler = this.$vm[methodName];
} if (!isFn(handler)) {
if (isOnce) { throw new Error(` _vm.${methodName} is not a function`)
if (handler.once) {
return
} }
handler.once = true; if (isOnce) {
} if (handler.once) {
handler.apply(this.$vm, processEventArgs(event, eventArray[1], isCustom)); return
}); }
} handler.once = true;
}); }
} handler.apply(this.$vm, processEventArgs(
this.$vm,
function initRefs (vm) { event,
const mpInstance = vm.$mp[vm.mpType]; eventArray[1],
Object.defineProperty(vm, '$refs', { eventArray[2],
get () { isCustom,
const $refs = Object.create(null); methodName
const components = mpInstance.selectAllComponents('.vue-ref'); ));
components.forEach(component => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm;
});
const forComponents = mpInstance.selectAllComponents('.vue-ref-in-for');
forComponents.forEach(component => {
const ref = component.dataset.ref;
if (!$refs[ref]) {
$refs[ref] = [];
} }
$refs[ref].push(component.$vm);
}); });
return $refs
} }
}); });
} }
const hooks = [ const hooks = [
'onShow',
'onHide', 'onHide',
'onError', 'onError',
'onPageNotFound' 'onPageNotFound',
'onUniNViewMessage'
]; ];
function createApp (vueOptions) { function initVm (vm) {
vueOptions = vueOptions.default || vueOptions; if (this.$vm) { // 百度竟然 onShow 在 onLaunch 之前?
return
}
this.$vm = vm;
this.$vm.$mp = {
app: this
};
}
function createApp (vm) {
// 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin // 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin
Vue.mixin({ Vue.mixin({
beforeCreate () { beforeCreate () {
...@@ -651,7 +807,6 @@ function createApp (vueOptions) { ...@@ -651,7 +807,6 @@ function createApp (vueOptions) {
delete this.$options.mpInstance; delete this.$options.mpInstance;
if (this.mpType !== 'app') { if (this.mpType !== 'app') {
initRefs(this);
initMocks(this); initMocks(this);
} }
}, },
...@@ -663,24 +818,69 @@ function createApp (vueOptions) { ...@@ -663,24 +818,69 @@ function createApp (vueOptions) {
const appOptions = { const appOptions = {
onLaunch (args) { onLaunch (args) {
this.$vm = new Vue(Object.assign(vueOptions, { initVm.call(this, vm);
mpType: 'app',
mpInstance: this
}));
this.$vm.$mount(); this.$vm._isMounted = true;
setTimeout(() => this.$vm.__call_hook('onLaunch', args)); this.$vm.__call_hook('mounted');
this.$vm.__call_hook('onLaunch', args);
},
onShow (args) {
initVm.call(this, vm);
this.$vm.__call_hook('onShow', args);
} }
}; };
initHooks(appOptions, hooks, true); // 延迟执行,因为 App 的注册在 main.js 之前,可能导致生命周期内 Vue 原型上开发者注册的属性无法访问 // 兼容旧版本 globalData
appOptions.globalData = vm.$options.globalData || {};
initHooks(appOptions, hooks); // 延迟执行,因为 App 的注册在 main.js 之前,可能导致生命周期内 Vue 原型上开发者注册的属性无法访问
App(appOptions); App(appOptions);
return vueOptions return vm
} }
const instances = Object.create(null); const instances = Object.create(null);
function initPage (pageOptions) {
initComponent(pageOptions);
}
function initComponent (componentOptions) {
if (componentOptions.properties) { // ref
componentOptions.properties.vueRef = {
type: String,
value: ''
};
}
const oldAttached = componentOptions.lifetimes.attached;
componentOptions.lifetimes.attached = function () {
oldAttached.call(this);
// TODO 需要处理动态变化后的 refs
initRefs$1.call(this);
};
}
function initRefs$1 () {
this.selectAllComponents('.vue-ref', (components) => {
components.forEach(component => {
const ref = component.data.vueRef; // 头条的组件 dataset 竟然是空的
this.$vm.$refs[ref] = component.$vm || component;
});
});
this.selectAllComponents('.vue-ref-in-for', (forComponents) => {
forComponents.forEach(component => {
const ref = component.data.vueRef;
if (!this.$vm.$refs[ref]) {
this.$vm.$refs[ref] = [];
}
this.$vm.$refs[ref].push(component.$vm || component);
});
});
}
function triggerLink (mpInstance) { function triggerLink (mpInstance) {
const nodeId = mpInstance.__nodeid__ + ''; const nodeId = mpInstance.__nodeid__ + '';
const webviewId = mpInstance.__webviewId__ + ''; const webviewId = mpInstance.__webviewId__ + '';
...@@ -727,63 +927,95 @@ const hooks$1 = [ ...@@ -727,63 +927,95 @@ const hooks$1 = [
'onNavigationBarSearchInputClicked' 'onNavigationBarSearchInputClicked'
]; ];
function initVm$1 (VueComponent) { // 百度的 onLoad 触发在 attached 之前
if (this.$vm) {
return
}
this.$vm = new VueComponent({
mpType: 'page',
mpInstance: this
});
this.$vm.__call_hook('created');
this.$vm.$mount();
}
function createPage (vueOptions) { function createPage (vueOptions) {
vueOptions = vueOptions.default || vueOptions; vueOptions = vueOptions.default || vueOptions;
let VueComponent;
if (isFn(vueOptions)) {
VueComponent = vueOptions;
vueOptions = VueComponent.extendOptions;
} else {
VueComponent = Vue.extend(vueOptions);
}
const pageOptions = { const pageOptions = {
data: getData(vueOptions), options: {
onLoad (args) { multipleSlots: true,
addGlobalClass: true
this.$vm = new Vue(Object.assign(vueOptions, {
mpType: 'page',
mpInstance: this
}));
this.$vm.__call_hook('created');
this.$vm.__call_hook('onLoad', args); // 开发者一般可能会在 onLoad 时赋值,所以提前到 mount 之前
this.$vm.$mount();
},
onReady () {
this.$vm._isMounted = true;
this.$vm.__call_hook('mounted');
this.$vm.__call_hook('onReady');
}, },
onUnload () { data: getData(vueOptions, Vue.prototype),
this.$vm.__call_hook('onUnload'); lifetimes: { // 当页面作为组件时
{ attached () {
initVm$1.call(this, VueComponent);
},
ready () {
this.$vm.__call_hook('beforeMount');
this.$vm._isMounted = true;
this.$vm.__call_hook('mounted');
this.$vm.__call_hook('onReady');
},
detached () {
this.$vm.$destroy(); this.$vm.$destroy();
} }
}, },
__e: handleEvent, methods: { // 作为页面时
__l: handleLink onLoad (args) {
initVm$1.call(this, VueComponent);
this.$vm.$mp.query = args; // 又要兼容 mpvue
this.$vm.__call_hook('onLoad', args); // 开发者可能会在 onLoad 时赋值,提前到 mount 之前
},
onUnload () {
this.$vm.__call_hook('onUnload');
},
__e: handleEvent,
__l: handleLink
}
}; };
initHooks(pageOptions, hooks$1); initHooks(pageOptions.methods, hooks$1);
initPage(pageOptions);
return Page(pageOptions) return Component(pageOptions)
} }
function initVueComponent (mpInstace, VueComponent, extraOptions = {}) { function initVm$2 (VueComponent) {
if (mpInstace.$vm) { if (this.$vm) {
return return
} }
const options = Object.assign({ const options = {
mpType: 'component', mpType: 'component',
mpInstance: mpInstace, mpInstance: this,
propsData: mpInstace.properties propsData: this.properties
}, extraOptions); };
// 初始化 vue 实例 // 初始化 vue 实例
mpInstace.$vm = new VueComponent(options); this.$vm = new VueComponent(options);
// 处理$slots,$scopedSlots(暂不支持动态变化$slots) // 处理$slots,$scopedSlots(暂不支持动态变化$slots)
const vueSlots = mpInstace.properties.vueSlots; const vueSlots = this.properties.vueSlots;
if (Array.isArray(vueSlots) && vueSlots.length) { if (Array.isArray(vueSlots) && vueSlots.length) {
const $slots = Object.create(null); const $slots = Object.create(null);
vueSlots.forEach(slotName => { vueSlots.forEach(slotName => {
$slots[slotName] = true; $slots[slotName] = true;
}); });
mpInstace.$vm.$scopedSlots = mpInstace.$vm.$slots = $slots; this.$vm.$scopedSlots = this.$vm.$slots = $slots;
} }
// 性能优先,mount 提前到 attached 中,保证组件首次渲染数据被合并
// 导致与标准 Vue 的差异,data 和 computed 中不能使用$parent,provide等组件属性
this.$vm.$mount();
} }
function createComponent (vueOptions) { function createComponent (vueOptions) {
...@@ -798,19 +1030,19 @@ function createComponent (vueOptions) { ...@@ -798,19 +1030,19 @@ function createComponent (vueOptions) {
multipleSlots: true, multipleSlots: true,
addGlobalClass: true addGlobalClass: true
}, },
data: getData(vueOptions), data: getData(vueOptions, Vue.prototype),
properties, properties,
lifetimes: { lifetimes: {
attached () { attached () {
initVueComponent(this, VueComponent); initVm$2.call(this, VueComponent);
}, },
ready () { ready () {
initVueComponent(this, VueComponent); // 目前发现部分情况小程序 attached 不触发 initVm$2.call(this, VueComponent); // 目前发现部分情况小程序 attached 不触发
triggerLink(this); // 处理 parent,children triggerLink(this); // 处理 parent,children
// 初始化渲染数据(需要等 parent,inject 都初始化完成,否则可以放到 attached 里边初始化渲染) // 补充生命周期
this.$vm.__call_hook('created'); this.$vm.__call_hook('created');
this.$vm.$mount(); this.$vm.__call_hook('beforeMount');
this.$vm._isMounted = true; this.$vm._isMounted = true;
this.$vm.__call_hook('mounted'); this.$vm.__call_hook('mounted');
this.$vm.__call_hook('onReady'); this.$vm.__call_hook('onReady');
...@@ -836,6 +1068,8 @@ function createComponent (vueOptions) { ...@@ -836,6 +1068,8 @@ function createComponent (vueOptions) {
} }
}; };
initComponent(componentOptions);
return Component(componentOptions) return Component(componentOptions)
} }
...@@ -849,12 +1083,14 @@ if (typeof Proxy !== 'undefined') { ...@@ -849,12 +1083,14 @@ if (typeof Proxy !== 'undefined') {
} }
if (api[name]) { if (api[name]) {
return promisify(name, api[name]) return promisify(name, api[name])
} }
if (extraApi[name]) { {
return promisify(name, extraApi[name]) if (extraApi[name]) {
} return promisify(name, extraApi[name])
if (todoApis[name]) { }
return promisify(name, todoApis[name]) if (todoApis[name]) {
return promisify(name, todoApis[name])
}
} }
if (!hasOwn(tt, name) && !hasOwn(protocols, name)) { if (!hasOwn(tt, name) && !hasOwn(protocols, name)) {
return return
...@@ -865,13 +1101,14 @@ if (typeof Proxy !== 'undefined') { ...@@ -865,13 +1101,14 @@ if (typeof Proxy !== 'undefined') {
} else { } else {
uni.upx2px = upx2px; uni.upx2px = upx2px;
Object.keys(todoApis).forEach(name => { {
uni[name] = promisify(name, todoApis[name]); Object.keys(todoApis).forEach(name => {
}); uni[name] = promisify(name, todoApis[name]);
});
Object.keys(extraApi).forEach(name => { Object.keys(extraApi).forEach(name => {
uni[name] = promisify(name, todoApis[name]); uni[name] = promisify(name, todoApis[name]);
}); });
}
Object.keys(api).forEach(name => { Object.keys(api).forEach(name => {
uni[name] = promisify(name, api[name]); uni[name] = promisify(name, api[name]);
......
{ {
"name": "@dcloudio/uni-mp-toutiao", "name": "@dcloudio/uni-mp-toutiao",
"version": "0.0.312", "version": "0.0.313",
"description": "uni-app mp-toutiao", "description": "uni-app mp-toutiao",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
......
...@@ -44,8 +44,6 @@ const SYNC_API_RE = /requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Syn ...@@ -44,8 +44,6 @@ const SYNC_API_RE = /requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Syn
const CONTEXT_API_RE = /^create|Manager$/; const CONTEXT_API_RE = /^create|Manager$/;
const TASK_APIS = ['request', 'downloadFile', 'uploadFile', 'connectSocket'];
const CALLBACK_API_RE = /^on/; const CALLBACK_API_RE = /^on/;
function isContextApi (name) { function isContextApi (name) {
...@@ -59,10 +57,6 @@ function isCallbackApi (name) { ...@@ -59,10 +57,6 @@ function isCallbackApi (name) {
return CALLBACK_API_RE.test(name) return CALLBACK_API_RE.test(name)
} }
function isTaskApi (name) {
return TASK_APIS.indexOf(name) !== -1
}
function handlePromise (promise) { function handlePromise (promise) {
return promise.then(data => { return promise.then(data => {
return [null, data] return [null, data]
...@@ -74,8 +68,7 @@ function shouldPromise (name) { ...@@ -74,8 +68,7 @@ function shouldPromise (name) {
if ( if (
isContextApi(name) || isContextApi(name) ||
isSyncApi(name) || isSyncApi(name) ||
isCallbackApi(name) || isCallbackApi(name)
isTaskApi(name)
) { ) {
return false return false
} }
...@@ -295,8 +288,8 @@ var api = /*#__PURE__*/Object.freeze({ ...@@ -295,8 +288,8 @@ var api = /*#__PURE__*/Object.freeze({
}); });
const WXPage = Page; const MPPage = Page;
const WXComponent = Component; const MPComponent = Component;
const customizeRE = /:/g; const customizeRE = /:/g;
...@@ -305,12 +298,10 @@ const customize = cached((str) => { ...@@ -305,12 +298,10 @@ const customize = cached((str) => {
}); });
function initTriggerEvent (mpInstance) { function initTriggerEvent (mpInstance) {
if (wx.canIUse('nextTick')) { // 微信旧版本基础库不支持重写triggerEvent const oldTriggerEvent = mpInstance.triggerEvent;
const oldTriggerEvent = mpInstance.triggerEvent; mpInstance.triggerEvent = function (event, ...args) {
mpInstance.triggerEvent = function (event, ...args) { return oldTriggerEvent.apply(mpInstance, [customize(event), ...args])
return oldTriggerEvent.apply(mpInstance, [customize(event), ...args]) };
};
}
} }
Page = function (options = {}) { Page = function (options = {}) {
...@@ -326,7 +317,7 @@ Page = function (options = {}) { ...@@ -326,7 +317,7 @@ Page = function (options = {}) {
return oldHook.apply(this, args) return oldHook.apply(this, args)
}; };
} }
return WXPage(options) return MPPage(options)
}; };
const behavior = Behavior({ const behavior = Behavior({
...@@ -337,10 +328,10 @@ const behavior = Behavior({ ...@@ -337,10 +328,10 @@ const behavior = Behavior({
Component = function (options = {}) { Component = function (options = {}) {
(options.behaviors || (options.behaviors = [])).unshift(behavior); (options.behaviors || (options.behaviors = [])).unshift(behavior);
return WXComponent(options) return MPComponent(options)
}; };
const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__']; const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__', '__webviewId__'];
function initMocks (vm) { function initMocks (vm) {
const mpInstance = vm.$mp[vm.mpType]; const mpInstance = vm.$mp[vm.mpType];
...@@ -542,7 +533,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam ...@@ -542,7 +533,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam
if (isCustomMPEvent) { if (isCustomMPEvent) {
return [event] return [event]
} }
return event.detail return event.detail.__args__ || event.detail
} }
} }
...@@ -555,7 +546,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam ...@@ -555,7 +546,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam
ret.push(event.target.value); ret.push(event.target.value);
} else { } else {
if (isCustom && !isCustomMPEvent) { if (isCustom && !isCustomMPEvent) {
ret.push(event.detail[0]); ret.push(event.detail.__args__[0]);
} else { // wxcomponent 组件或内置组件 } else { // wxcomponent 组件或内置组件
ret.push(event); ret.push(event);
} }
...@@ -627,7 +618,7 @@ function initRefs (vm) { ...@@ -627,7 +618,7 @@ function initRefs (vm) {
const mpInstance = vm.$mp[vm.mpType]; const mpInstance = vm.$mp[vm.mpType];
Object.defineProperty(vm, '$refs', { Object.defineProperty(vm, '$refs', {
get () { get () {
const $refs = Object.create(null); const $refs = {};
const components = mpInstance.selectAllComponents('.vue-ref'); const components = mpInstance.selectAllComponents('.vue-ref');
components.forEach(component => { components.forEach(component => {
const ref = component.dataset.ref; const ref = component.dataset.ref;
...@@ -647,13 +638,29 @@ function initRefs (vm) { ...@@ -647,13 +638,29 @@ function initRefs (vm) {
} }
const hooks = [ const hooks = [
'onShow',
'onHide', 'onHide',
'onError', 'onError',
'onPageNotFound', 'onPageNotFound',
'onUniNViewMessage' 'onUniNViewMessage'
]; ];
function initVm (vm) {
if (this.$vm) { // 百度竟然 onShow 在 onLaunch 之前?
return
}
{
if (!wx.canIUse('nextTick')) { // 事实 上2.2.3 即可,简单使用 2.3.0 的 nextTick 判断
console.error('当前微信基础库版本过低,请将 微信开发者工具-详情-项目设置-调试基础库版本 更换为`2.3.0`以上');
}
}
this.$vm = vm;
this.$vm.$mp = {
app: this
};
}
function createApp (vm) { function createApp (vm) {
// 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin // 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin
Vue.mixin({ Vue.mixin({
...@@ -670,7 +677,9 @@ function createApp (vm) { ...@@ -670,7 +677,9 @@ function createApp (vm) {
delete this.$options.mpInstance; delete this.$options.mpInstance;
if (this.mpType !== 'app') { if (this.mpType !== 'app') {
initRefs(this); { // 头条的 selectComponent 竟然是异步的
initRefs(this);
}
initMocks(this); initMocks(this);
} }
}, },
...@@ -682,22 +691,17 @@ function createApp (vm) { ...@@ -682,22 +691,17 @@ function createApp (vm) {
const appOptions = { const appOptions = {
onLaunch (args) { onLaunch (args) {
{ initVm.call(this, vm);
if (!wx.canIUse('nextTick')) { // 事实 上2.2.3 即可,简单使用 2.3.0 的 nextTick 判断
console.error('当前微信基础库版本过低,请将 微信开发者工具-详情-项目设置-调试基础库版本 更换为`2.3.0`以上');
}
}
this.$vm = vm;
this.$vm.$mp = {
app: this
};
this.$vm._isMounted = true; this.$vm._isMounted = true;
this.$vm.__call_hook('mounted'); this.$vm.__call_hook('mounted');
this.$vm.__call_hook('onLaunch', args); this.$vm.__call_hook('onLaunch', args);
},
onShow (args) {
initVm.call(this, vm);
this.$vm.__call_hook('onShow', args);
} }
}; };
...@@ -749,6 +753,20 @@ const hooks$1 = [ ...@@ -749,6 +753,20 @@ const hooks$1 = [
'onNavigationBarSearchInputClicked' 'onNavigationBarSearchInputClicked'
]; ];
function initVm$1 (VueComponent) { // 百度的 onLoad 触发在 attached 之前
if (this.$vm) {
return
}
this.$vm = new VueComponent({
mpType: 'page',
mpInstance: this
});
this.$vm.__call_hook('created');
this.$vm.$mount();
}
function createPage (vueOptions) { function createPage (vueOptions) {
vueOptions = vueOptions.default || vueOptions; vueOptions = vueOptions.default || vueOptions;
let VueComponent; let VueComponent;
...@@ -766,14 +784,7 @@ function createPage (vueOptions) { ...@@ -766,14 +784,7 @@ function createPage (vueOptions) {
data: getData(vueOptions, Vue.prototype), data: getData(vueOptions, Vue.prototype),
lifetimes: { // 当页面作为组件时 lifetimes: { // 当页面作为组件时
attached () { attached () {
initVm$1.call(this, VueComponent);
this.$vm = new VueComponent({
mpType: 'page',
mpInstance: this
});
this.$vm.__call_hook('created');
this.$vm.$mount();
}, },
ready () { ready () {
this.$vm.__call_hook('beforeMount'); this.$vm.__call_hook('beforeMount');
...@@ -787,6 +798,7 @@ function createPage (vueOptions) { ...@@ -787,6 +798,7 @@ function createPage (vueOptions) {
}, },
methods: { // 作为页面时 methods: { // 作为页面时
onLoad (args) { onLoad (args) {
initVm$1.call(this, VueComponent);
this.$vm.$mp.query = args; // 又要兼容 mpvue this.$vm.$mp.query = args; // 又要兼容 mpvue
this.$vm.__call_hook('onLoad', args); // 开发者可能会在 onLoad 时赋值,提前到 mount 之前 this.$vm.__call_hook('onLoad', args); // 开发者可能会在 onLoad 时赋值,提前到 mount 之前
}, },
...@@ -803,31 +815,31 @@ function createPage (vueOptions) { ...@@ -803,31 +815,31 @@ function createPage (vueOptions) {
return Component(pageOptions) return Component(pageOptions)
} }
function initVueComponent (mpInstace, VueComponent, extraOptions = {}) { function initVm$2 (VueComponent) {
if (mpInstace.$vm) { if (this.$vm) {
return return
} }
const options = Object.assign({ const options = {
mpType: 'component', mpType: 'component',
mpInstance: mpInstace, mpInstance: this,
propsData: mpInstace.properties propsData: this.properties
}, extraOptions); };
// 初始化 vue 实例 // 初始化 vue 实例
mpInstace.$vm = new VueComponent(options); this.$vm = new VueComponent(options);
// 处理$slots,$scopedSlots(暂不支持动态变化$slots) // 处理$slots,$scopedSlots(暂不支持动态变化$slots)
const vueSlots = mpInstace.properties.vueSlots; const vueSlots = this.properties.vueSlots;
if (Array.isArray(vueSlots) && vueSlots.length) { if (Array.isArray(vueSlots) && vueSlots.length) {
const $slots = Object.create(null); const $slots = Object.create(null);
vueSlots.forEach(slotName => { vueSlots.forEach(slotName => {
$slots[slotName] = true; $slots[slotName] = true;
}); });
mpInstace.$vm.$scopedSlots = mpInstace.$vm.$slots = $slots; this.$vm.$scopedSlots = this.$vm.$slots = $slots;
} }
// 性能优先,mount 提前到 attached 中,保证组件首次渲染数据被合并 // 性能优先,mount 提前到 attached 中,保证组件首次渲染数据被合并
// 导致与标准 Vue 的差异,data 和 computed 中不能使用$parent,provide等组件属性 // 导致与标准 Vue 的差异,data 和 computed 中不能使用$parent,provide等组件属性
mpInstace.$vm.$mount(); this.$vm.$mount();
} }
function createComponent (vueOptions) { function createComponent (vueOptions) {
...@@ -846,10 +858,10 @@ function createComponent (vueOptions) { ...@@ -846,10 +858,10 @@ function createComponent (vueOptions) {
properties, properties,
lifetimes: { lifetimes: {
attached () { attached () {
initVueComponent(this, VueComponent); initVm$2.call(this, VueComponent);
}, },
ready () { ready () {
initVueComponent(this, VueComponent); // 目前发现部分情况小程序 attached 不触发 initVm$2.call(this, VueComponent); // 目前发现部分情况小程序 attached 不触发
triggerLink(this); // 处理 parent,children triggerLink(this); // 处理 parent,children
// 补充生命周期 // 补充生命周期
......
{ {
"name": "@dcloudio/uni-mp-weixin", "name": "@dcloudio/uni-mp-weixin",
"version": "0.0.935", "version": "0.0.936",
"description": "uni-app mp-weixin", "description": "uni-app mp-weixin",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
......
...@@ -36,8 +36,7 @@ export function shouldPromise (name) { ...@@ -36,8 +36,7 @@ export function shouldPromise (name) {
if ( if (
isContextApi(name) || isContextApi(name) ||
isSyncApi(name) || isSyncApi(name) ||
isCallbackApi(name) || isCallbackApi(name)
isTaskApi(name)
) { ) {
return false return false
} }
......
...@@ -9,13 +9,29 @@ import { ...@@ -9,13 +9,29 @@ import {
} from './util' } from './util'
const hooks = [ const hooks = [
'onShow',
'onHide', 'onHide',
'onError', 'onError',
'onPageNotFound', 'onPageNotFound',
'onUniNViewMessage' 'onUniNViewMessage'
] ]
function initVm (vm) {
if (this.$vm) { // 百度竟然 onShow 在 onLaunch 之前?
return
}
if (__PLATFORM__ === 'mp-weixin') {
if (!wx.canIUse('nextTick')) { // 事实 上2.2.3 即可,简单使用 2.3.0 的 nextTick 判断
console.error('当前微信基础库版本过低,请将 微信开发者工具-详情-项目设置-调试基础库版本 更换为`2.3.0`以上')
}
}
this.$vm = vm
this.$vm.$mp = {
app: this
}
}
export function createApp (vm) { export function createApp (vm) {
// 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin // 外部初始化时 Vue 还未初始化,放到 createApp 内部初始化 mixin
Vue.mixin({ Vue.mixin({
...@@ -32,7 +48,9 @@ export function createApp (vm) { ...@@ -32,7 +48,9 @@ export function createApp (vm) {
delete this.$options.mpInstance delete this.$options.mpInstance
if (this.mpType !== 'app') { if (this.mpType !== 'app') {
initRefs(this) if (__PLATFORM__ !== 'mp-toutiao') { // 头条的 selectComponent 竟然是异步的
initRefs(this)
}
initMocks(this) initMocks(this)
} }
}, },
...@@ -44,22 +62,17 @@ export function createApp (vm) { ...@@ -44,22 +62,17 @@ export function createApp (vm) {
const appOptions = { const appOptions = {
onLaunch (args) { onLaunch (args) {
if (__PLATFORM__ === 'mp-weixin') { initVm.call(this, vm)
if (!wx.canIUse('nextTick')) { // 事实 上2.2.3 即可,简单使用 2.3.0 的 nextTick 判断
console.error('当前微信基础库版本过低,请将 微信开发者工具-详情-项目设置-调试基础库版本 更换为`2.3.0`以上')
}
}
this.$vm = vm
this.$vm.$mp = {
app: this
}
this.$vm._isMounted = true this.$vm._isMounted = true
this.$vm.__call_hook('mounted') this.$vm.__call_hook('mounted')
this.$vm.__call_hook('onLaunch', args) this.$vm.__call_hook('onLaunch', args)
},
onShow (args) {
initVm.call(this, vm)
this.$vm.__call_hook('onShow', args)
} }
} }
......
...@@ -2,7 +2,8 @@ import Vue from 'vue' ...@@ -2,7 +2,8 @@ import Vue from 'vue'
import { import {
handleLink, handleLink,
triggerLink triggerLink,
initComponent
} from 'uni-platform/runtime/wrapper/index' } from 'uni-platform/runtime/wrapper/index'
import { import {
...@@ -11,31 +12,31 @@ import { ...@@ -11,31 +12,31 @@ import {
getProperties getProperties
} from './util' } from './util'
function initVueComponent (mpInstace, VueComponent, extraOptions = {}) { function initVm (VueComponent) {
if (mpInstace.$vm) { if (this.$vm) {
return return
} }
const options = Object.assign({ const options = {
mpType: 'component', mpType: 'component',
mpInstance: mpInstace, mpInstance: this,
propsData: mpInstace.properties propsData: this.properties
}, extraOptions) }
// 初始化 vue 实例 // 初始化 vue 实例
mpInstace.$vm = new VueComponent(options) this.$vm = new VueComponent(options)
// 处理$slots,$scopedSlots(暂不支持动态变化$slots) // 处理$slots,$scopedSlots(暂不支持动态变化$slots)
const vueSlots = mpInstace.properties.vueSlots const vueSlots = this.properties.vueSlots
if (Array.isArray(vueSlots) && vueSlots.length) { if (Array.isArray(vueSlots) && vueSlots.length) {
const $slots = Object.create(null) const $slots = Object.create(null)
vueSlots.forEach(slotName => { vueSlots.forEach(slotName => {
$slots[slotName] = true $slots[slotName] = true
}) })
mpInstace.$vm.$scopedSlots = mpInstace.$vm.$slots = $slots this.$vm.$scopedSlots = this.$vm.$slots = $slots
} }
// 性能优先,mount 提前到 attached 中,保证组件首次渲染数据被合并 // 性能优先,mount 提前到 attached 中,保证组件首次渲染数据被合并
// 导致与标准 Vue 的差异,data 和 computed 中不能使用$parent,provide等组件属性 // 导致与标准 Vue 的差异,data 和 computed 中不能使用$parent,provide等组件属性
mpInstace.$vm.$mount() this.$vm.$mount()
} }
export function createComponent (vueOptions) { export function createComponent (vueOptions) {
...@@ -54,10 +55,10 @@ export function createComponent (vueOptions) { ...@@ -54,10 +55,10 @@ export function createComponent (vueOptions) {
properties, properties,
lifetimes: { lifetimes: {
attached () { attached () {
initVueComponent(this, VueComponent) initVm.call(this, VueComponent)
}, },
ready () { ready () {
initVueComponent(this, VueComponent) // 目前发现部分情况小程序 attached 不触发 initVm.call(this, VueComponent) // 目前发现部分情况小程序 attached 不触发
triggerLink(this) // 处理 parent,children triggerLink(this) // 处理 parent,children
// 补充生命周期 // 补充生命周期
...@@ -68,9 +69,6 @@ export function createComponent (vueOptions) { ...@@ -68,9 +69,6 @@ export function createComponent (vueOptions) {
this.$vm.__call_hook('onReady') this.$vm.__call_hook('onReady')
}, },
detached () { detached () {
if (__PLATFORM__ === 'mp-baidu') {
delete this.pageinstance.$baiduComponentInstances[this.id]
}
this.$vm.$destroy() this.$vm.$destroy()
} }
}, },
...@@ -91,5 +89,7 @@ export function createComponent (vueOptions) { ...@@ -91,5 +89,7 @@ export function createComponent (vueOptions) {
} }
} }
initComponent(componentOptions)
return Component(componentOptions) return Component(componentOptions)
} }
...@@ -4,7 +4,8 @@ import { ...@@ -4,7 +4,8 @@ import {
isFn isFn
} from 'uni-shared' } from 'uni-shared'
import { import {
initPage,
handleLink handleLink
} from 'uni-platform/runtime/wrapper/index' } from 'uni-platform/runtime/wrapper/index'
...@@ -31,6 +32,24 @@ const hooks = [ ...@@ -31,6 +32,24 @@ const hooks = [
'onNavigationBarSearchInputClicked' 'onNavigationBarSearchInputClicked'
] ]
function initVm (VueComponent) { // 百度的 onLoad 触发在 attached 之前
if (this.$vm) {
return
}
this.$vm = new VueComponent({
mpType: 'page',
mpInstance: this
})
if (__PLATFORM__ === 'mp-baidu') {
this.$vm.$baiduComponentInstances = Object.create(null)
}
this.$vm.__call_hook('created')
this.$vm.$mount()
}
export function createPage (vueOptions) { export function createPage (vueOptions) {
vueOptions = vueOptions.default || vueOptions vueOptions = vueOptions.default || vueOptions
let VueComponent let VueComponent
...@@ -48,17 +67,7 @@ export function createPage (vueOptions) { ...@@ -48,17 +67,7 @@ export function createPage (vueOptions) {
data: getData(vueOptions, Vue.prototype), data: getData(vueOptions, Vue.prototype),
lifetimes: { // 当页面作为组件时 lifetimes: { // 当页面作为组件时
attached () { attached () {
if (__PLATFORM__ === 'mp-baidu') { initVm.call(this, VueComponent)
this.$baiduComponentInstances = Object.create(null)
}
this.$vm = new VueComponent({
mpType: 'page',
mpInstance: this
})
this.$vm.__call_hook('created')
this.$vm.$mount()
}, },
ready () { ready () {
this.$vm.__call_hook('beforeMount') this.$vm.__call_hook('beforeMount')
...@@ -72,6 +81,10 @@ export function createPage (vueOptions) { ...@@ -72,6 +81,10 @@ export function createPage (vueOptions) {
}, },
methods: { // 作为页面时 methods: { // 作为页面时
onLoad (args) { onLoad (args) {
initVm.call(this, VueComponent)
if (__PLATFORM__ === 'mp-baidu') { // 百度当组件作为页面时 pageinstancce 不是原来组件的 instance
this.pageinstance.$vm = this.$vm
}
this.$vm.$mp.query = args // 又要兼容 mpvue this.$vm.$mp.query = args // 又要兼容 mpvue
this.$vm.__call_hook('onLoad', args) // 开发者可能会在 onLoad 时赋值,提前到 mount 之前 this.$vm.__call_hook('onLoad', args) // 开发者可能会在 onLoad 时赋值,提前到 mount 之前
}, },
...@@ -87,12 +100,8 @@ export function createPage (vueOptions) { ...@@ -87,12 +100,8 @@ export function createPage (vueOptions) {
} }
initHooks(pageOptions.methods, hooks) initHooks(pageOptions.methods, hooks)
if (__PLATFORM__ === 'app-plus') { initPage(pageOptions)
pageOptions.methods.$getAppWebview = function () {
return plus.webview.getWebviewById(`${this.__wxWebviewId__}`)
}
}
return Component(pageOptions) return Component(pageOptions)
} }
...@@ -5,7 +5,7 @@ import { ...@@ -5,7 +5,7 @@ import {
isPlainObject isPlainObject
} from 'uni-shared' } from 'uni-shared'
const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__'] const MOCKS = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__', '__webviewId__']
export function initMocks (vm) { export function initMocks (vm) {
const mpInstance = vm.$mp[vm.mpType] const mpInstance = vm.$mp[vm.mpType]
...@@ -217,7 +217,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam ...@@ -217,7 +217,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam
if (isCustomMPEvent) { if (isCustomMPEvent) {
return [event] return [event]
} }
return event.detail return event.detail.__args__ || event.detail
} }
} }
...@@ -230,7 +230,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam ...@@ -230,7 +230,7 @@ function processEventArgs (vm, event, args = [], extra = [], isCustom, methodNam
ret.push(event.target.value) ret.push(event.target.value)
} else { } else {
if (isCustom && !isCustomMPEvent) { if (isCustom && !isCustomMPEvent) {
ret.push(event.detail[0]) ret.push(event.detail.__args__[0])
} else { // wxcomponent 组件或内置组件 } else { // wxcomponent 组件或内置组件
ret.push(event) ret.push(event)
} }
...@@ -302,7 +302,7 @@ export function initRefs (vm) { ...@@ -302,7 +302,7 @@ export function initRefs (vm) {
const mpInstance = vm.$mp[vm.mpType] const mpInstance = vm.$mp[vm.mpType]
Object.defineProperty(vm, '$refs', { Object.defineProperty(vm, '$refs', {
get () { get () {
const $refs = Object.create(null) const $refs = {}
const components = mpInstance.selectAllComponents('.vue-ref') const components = mpInstance.selectAllComponents('.vue-ref')
components.forEach(component => { components.forEach(component => {
const ref = component.dataset.ref const ref = component.dataset.ref
......
export function triggerLink (mpInstance, vueOptions) { export {
mpInstance.triggerEvent('__l', mpInstance.$vm || vueOptions, { handleLink,
bubbles: true, triggerLink
composed: true
})
} }
from '../../../mp-weixin/runtime/wrapper/index'
export function handleLink (event) { export function initPage (pageOptions) {
if (event.detail.$mp) { // vm initComponent(pageOptions)
if (!event.detail.$parent) { }
event.detail.$parent = this.$vm
event.detail.$parent.$children.push(event.detail)
event.detail.$root = this.$vm.$root export function initComponent (componentOptions) {
} componentOptions.methods.$getAppWebview = function () {
} else { // vueOptions return plus.webview.getWebviewById(`${this.__wxWebviewId__}`)
if (!event.detail.parent) {
event.detail.parent = this.$vm
}
} }
} }
export function triggerLink (mpInstance) { export function initPage (pageOptions) {
const baiduComponentInstances = mpInstance.pageinstance.$baiduComponentInstances initComponent(pageOptions)
}
baiduComponentInstances[mpInstance.id] = mpInstance export function initComponent (componentOptions) {
if (mpInstance.ownerId) { // 组件嵌组件 componentOptions.messages = {
const parentBaiduComponentInstance = baiduComponentInstances[mpInstance.ownerId] '__l': handleLink
if (parentBaiduComponentInstance) {
handleLink.call(parentBaiduComponentInstance, {
detail: mpInstance
})
} else {
console.error(`查找父组件失败${mpInstance.ownerId}`)
}
} else { // 页面直属组件
handleLink.call(mpInstance.pageinstance, {
detail: mpInstance
})
} }
} }
export function triggerLink (mpInstance, vueOptions) {
mpInstance.dispatch('__l', mpInstance.$vm || vueOptions)
}
export function handleLink (event) { export function handleLink (event) {
if (!event.detail.$parent) { const target = event.value
event.detail.$parent = this.$vm if (target.$mp) {
event.detail.$parent.$children.push(event.detail) if (!target.$parent) {
target.$parent = this.$vm
target.$parent.$children.push(target)
event.detail.$root = this.$vm.$root target.$root = this.$vm.$root
}
} else {
if (!target.parent) {
target.parent = this.$vm
}
} }
} }
const instances = Object.create(null) const instances = Object.create(null)
export function initPage (pageOptions) {
initComponent(pageOptions)
}
export function initComponent (componentOptions) {
if (componentOptions.properties) { // ref
componentOptions.properties.vueRef = {
type: String,
value: ''
}
}
const oldAttached = componentOptions.lifetimes.attached
componentOptions.lifetimes.attached = function () {
oldAttached.call(this)
// TODO 需要处理动态变化后的 refs
initRefs.call(this)
}
}
function initRefs () {
this.selectAllComponents('.vue-ref', (components) => {
components.forEach(component => {
const ref = component.data.vueRef // 头条的组件 dataset 竟然是空的
this.$vm.$refs[ref] = component.$vm || component
})
})
this.selectAllComponents('.vue-ref-in-for', (forComponents) => {
forComponents.forEach(component => {
const ref = component.data.vueRef
if (!this.$vm.$refs[ref]) {
this.$vm.$refs[ref] = []
}
this.$vm.$refs[ref].push(component.$vm || component)
})
})
}
export function triggerLink (mpInstance) { export function triggerLink (mpInstance) {
const nodeId = mpInstance.__nodeid__ + '' const nodeId = mpInstance.__nodeid__ + ''
const webviewId = mpInstance.__webviewId__ + '' const webviewId = mpInstance.__webviewId__ + ''
......
...@@ -3,8 +3,8 @@ import { ...@@ -3,8 +3,8 @@ import {
camelize camelize
} from 'uni-shared' } from 'uni-shared'
const WXPage = Page const MPPage = Page
const WXComponent = Component const MPComponent = Component
const customizeRE = /:/g const customizeRE = /:/g
...@@ -13,11 +13,9 @@ const customize = cached((str) => { ...@@ -13,11 +13,9 @@ const customize = cached((str) => {
}) })
function initTriggerEvent (mpInstance) { function initTriggerEvent (mpInstance) {
if (wx.canIUse('nextTick')) { // 微信旧版本基础库不支持重写triggerEvent const oldTriggerEvent = mpInstance.triggerEvent
const oldTriggerEvent = mpInstance.triggerEvent mpInstance.triggerEvent = function (event, ...args) {
mpInstance.triggerEvent = function (event, ...args) { return oldTriggerEvent.apply(mpInstance, [customize(event), ...args])
return oldTriggerEvent.apply(mpInstance, [customize(event), ...args])
}
} }
} }
...@@ -34,7 +32,7 @@ Page = function (options = {}) { ...@@ -34,7 +32,7 @@ Page = function (options = {}) {
return oldHook.apply(this, args) return oldHook.apply(this, args)
} }
} }
return WXPage(options) return MPPage(options)
} }
const behavior = Behavior({ const behavior = Behavior({
...@@ -45,5 +43,5 @@ const behavior = Behavior({ ...@@ -45,5 +43,5 @@ const behavior = Behavior({
Component = function (options = {}) { Component = function (options = {}) {
(options.behaviors || (options.behaviors = [])).unshift(behavior) (options.behaviors || (options.behaviors = [])).unshift(behavior)
return WXComponent(options) return MPComponent(options)
} }
export function initPage () {
}
export function initComponent () {
}
export function triggerLink (mpInstance, vueOptions) { export function triggerLink (mpInstance, vueOptions) {
mpInstance.triggerEvent('__l', mpInstance.$vm || vueOptions, { mpInstance.triggerEvent('__l', mpInstance.$vm || vueOptions, {
bubbles: true, bubbles: true,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册