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

build uni runtime

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