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

feat(mp): add internal method

上级 dba4dee4
......@@ -462,6 +462,114 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
}
}, RemoveInterceptorProtocol);
const API_ON = '$on';
const OnProtocol = [
{
name: 'event',
type: String,
required: true,
},
{
name: 'callback',
type: Function,
required: true,
},
];
const API_ONCE = '$once';
const OnceProtocol = OnProtocol;
const API_OFF = '$off';
const OffProtocol = [
{
name: 'event',
type: [String, Array],
},
{
name: 'callback',
type: Function,
},
];
const API_EMIT = '$emit';
const EmitProtocol = [
{
name: 'event',
type: String,
required: true,
},
];
const E = function () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
};
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx,
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener() {
self.off(name, listener);
callback.apply(ctx, arguments);
}
listener._ = callback;
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
liveEvents.length ? (e[name] = liveEvents) : delete e[name];
return this;
},
};
var Emitter = E;
const emitter = new Emitter();
const $on = defineSyncApi(API_ON, (name, callback) => {
emitter.on(name, callback);
return () => emitter.off(name, callback);
}, OnProtocol);
const $once = defineSyncApi(API_ONCE, (name, callback) => {
emitter.once(name, callback);
return () => emitter.off(name, callback);
}, OnceProtocol);
const $off = defineSyncApi(API_OFF, (name, callback) => {
if (!name) {
emitter.e = {};
return;
}
if (!Array.isArray(name))
name = [name];
name.forEach((n) => emitter.off(n, callback));
}, OffProtocol);
const $emit = defineSyncApi(API_EMIT, (name, ...args) => {
emitter.emit(name, ...args);
}, EmitProtocol);
const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/;
const CONTEXT_API_RE = /^create|Manager$/;
// Context例外情况
......@@ -606,7 +714,15 @@ function initWrapper(protocols) {
};
}
const baseApis = { upx2px, addInterceptor, removeInterceptor };
const baseApis = {
$on,
$off,
$once,
$emit,
upx2px,
addInterceptor,
removeInterceptor,
};
function initUni(api, protocols) {
const wrapper = initWrapper(protocols);
const UniProxyHandlers = {
......
import { isPlainObject, hasOwn, isArray, toNumber, isObject, capitalize, isFunction, extend, NOOP, EMPTY_OBJ, camelize } from '@vue/shared';
import { isPlainObject, isArray, extend, hyphenate, isObject, hasOwn, toNumber, capitalize, isFunction, NOOP, EMPTY_OBJ, camelize } from '@vue/shared';
const encode = encodeURIComponent;
function stringifyQuery(obj, encodeStr = encode) {
......@@ -19,6 +19,14 @@ function stringifyQuery(obj, encodeStr = encode) {
: null;
return res ? `?${res}` : '';
}
function cache(fn) {
const cache = Object.create(null);
return (str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
const invokeArrayFns = (fns, arg) => {
let ret;
for (let i = 0; i < fns.length; i++) {
......@@ -121,6 +129,167 @@ function getEventChannel(id) {
return eventChannelStack.shift();
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
function getTarget(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (!obj) {
obj = {};
}
if (parts.length === 1) {
return obj[key];
}
return getTarget(obj[key], parts.slice(1).join('.'));
}
function getValue(dataPath, target) {
return getTarget(target || this, dataPath);
}
function getClass(dynamicClass, staticClass) {
return renderClass(staticClass, dynamicClass);
}
function getStyle(dynamicStyle, staticStyle) {
if (!dynamicStyle && !staticStyle) {
return '';
}
var dynamicStyleObj = normalizeStyleBinding(dynamicStyle);
var styleObj = staticStyle
? extend(staticStyle, dynamicStyleObj)
: dynamicStyleObj;
return Object.keys(styleObj)
.map(function (name) {
return hyphenate(name) + ':' + styleObj[name];
})
.join(';');
}
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
function normalizeStyleBinding(bindingStyle) {
if (Array.isArray(bindingStyle)) {
return toObject(bindingStyle);
}
if (typeof bindingStyle === 'string') {
return parseStyleText(bindingStyle);
}
return bindingStyle;
}
var parseStyleText = cache(function parseStyleText(cssText) {
var res = {};
var listDelimiter = /;(?![^(]*\))/g;
var propertyDelimiter = /:(.+)/;
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
var tmp = item.split(propertyDelimiter);
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
}
});
return res;
});
function isDef(v) {
return v !== undefined && v !== null;
}
function renderClass(staticClass, dynamicClass) {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass));
}
/* istanbul ignore next */
return '';
}
function concat(a, b) {
return a ? (b ? a + ' ' + b : a) : b || '';
}
function stringifyClass(value) {
if (Array.isArray(value)) {
return stringifyArray(value);
}
if (isObject(value)) {
return stringifyObject(value);
}
if (typeof value === 'string') {
return value;
}
/* istanbul ignore next */
return '';
}
function stringifyArray(value) {
var res = '';
var stringified;
for (var i = 0, l = value.length; i < l; i++) {
if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') {
if (res) {
res += ' ';
}
res += stringified;
}
}
return res;
}
function stringifyObject(value) {
var res = '';
for (var key in value) {
if (value[key]) {
if (res) {
res += ' ';
}
res += key;
}
}
return res;
}
function setModel(target, key, value, modifiers) {
if (isArray(modifiers)) {
if (modifiers.indexOf('trim') !== -1) {
......@@ -239,7 +408,9 @@ function initComponentInstance(instance, options) {
ctx.__set_sync = setSync;
ctx.__get_orig = getOrig;
// TODO
// ctx.__get_style = getStyle
ctx.__get_value = getValue;
ctx.__get_class = getClass;
ctx.__get_style = getStyle;
ctx.__map = map;
}
function initMocks(instance, mpInstance, mocks) {
......@@ -366,50 +537,6 @@ function initCreateApp(parseAppOptions) {
};
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
function parsePropType(key, type, defaultValue) {
// [String]=>String
......@@ -556,18 +683,6 @@ function initBehaviors(vueOptions, initBehavior) {
return behaviors;
}
function getValue(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (parts.length === 1) {
return obj[key];
}
return getValue(obj[key], parts.slice(1).join('.'));
}
function getExtraValue(instance, dataPathsArray) {
let context = instance;
dataPathsArray.forEach((dataPathArray) => {
......@@ -589,7 +704,7 @@ function getExtraValue(instance, dataPathsArray) {
vFor = dataPath.substr(3);
}
else {
vFor = getValue(context, dataPath);
vFor = getTarget(context, dataPath);
}
}
if (Number.isInteger(vFor)) {
......@@ -601,12 +716,12 @@ function getExtraValue(instance, dataPathsArray) {
else {
if (isArray(vFor)) {
context = vFor.find((vForItem) => {
return getValue(vForItem, propPath) === value;
return getTarget(vForItem, propPath) === value;
});
}
else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find((vForKey) => {
return getValue(vFor[vForKey], propPath) === value;
return getTarget(vFor[vForKey], propPath) === value;
});
}
else {
......@@ -614,7 +729,7 @@ function getExtraValue(instance, dataPathsArray) {
}
}
if (valuePath) {
context = getValue(context, valuePath);
context = getTarget(context, valuePath);
}
}
});
......@@ -655,10 +770,10 @@ function processEventExtra(instance, extra, event) {
}
else if (dataPath.indexOf('$event.') === 0) {
// $event.target.value
extraObj['$' + index] = getValue(event, dataPath.replace('$event.', ''));
extraObj['$' + index] = getTarget(event, dataPath.replace('$event.', ''));
}
else {
extraObj['$' + index] = getValue(instance, dataPath);
extraObj['$' + index] = getTarget(instance, dataPath);
}
}
}
......@@ -795,7 +910,14 @@ function handleEvent(event) {
}
handler.once = true;
}
ret.push(handler.apply(handlerCtx, processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName)));
let params = processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName);
params = Array.isArray(params) ? params : [];
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) {
// eslint-disable-next-line no-sparse-arrays
params = params.concat([, , , , , , , , , , event]);
}
ret.push(handler.apply(handlerCtx, params));
}
});
}
......
......@@ -462,6 +462,114 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
}
}, RemoveInterceptorProtocol);
const API_ON = '$on';
const OnProtocol = [
{
name: 'event',
type: String,
required: true,
},
{
name: 'callback',
type: Function,
required: true,
},
];
const API_ONCE = '$once';
const OnceProtocol = OnProtocol;
const API_OFF = '$off';
const OffProtocol = [
{
name: 'event',
type: [String, Array],
},
{
name: 'callback',
type: Function,
},
];
const API_EMIT = '$emit';
const EmitProtocol = [
{
name: 'event',
type: String,
required: true,
},
];
const E = function () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
};
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx,
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener() {
self.off(name, listener);
callback.apply(ctx, arguments);
}
listener._ = callback;
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
liveEvents.length ? (e[name] = liveEvents) : delete e[name];
return this;
},
};
var Emitter = E;
const emitter = new Emitter();
const $on = defineSyncApi(API_ON, (name, callback) => {
emitter.on(name, callback);
return () => emitter.off(name, callback);
}, OnProtocol);
const $once = defineSyncApi(API_ONCE, (name, callback) => {
emitter.once(name, callback);
return () => emitter.off(name, callback);
}, OnceProtocol);
const $off = defineSyncApi(API_OFF, (name, callback) => {
if (!name) {
emitter.e = {};
return;
}
if (!Array.isArray(name))
name = [name];
name.forEach((n) => emitter.off(n, callback));
}, OffProtocol);
const $emit = defineSyncApi(API_EMIT, (name, ...args) => {
emitter.emit(name, ...args);
}, EmitProtocol);
const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/;
const CONTEXT_API_RE = /^create|Manager$/;
// Context例外情况
......@@ -606,7 +714,15 @@ function initWrapper(protocols) {
};
}
const baseApis = { upx2px, addInterceptor, removeInterceptor };
const baseApis = {
$on,
$off,
$once,
$emit,
upx2px,
addInterceptor,
removeInterceptor,
};
function initUni(api, protocols) {
const wrapper = initWrapper(protocols);
const UniProxyHandlers = {
......
import { isPlainObject, isArray, hasOwn, toNumber, isObject, isFunction, extend, NOOP, camelize } from '@vue/shared';
import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared';
const encode = encodeURIComponent;
function stringifyQuery(obj, encodeStr = encode) {
......@@ -19,6 +19,14 @@ function stringifyQuery(obj, encodeStr = encode) {
: null;
return res ? `?${res}` : '';
}
function cache(fn) {
const cache = Object.create(null);
return (str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
const invokeArrayFns = (fns, arg) => {
let ret;
for (let i = 0; i < fns.length; i++) {
......@@ -120,6 +128,202 @@ function getEventChannel(id) {
return eventChannelStack.shift();
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
function getTarget(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (!obj) {
obj = {};
}
if (parts.length === 1) {
return obj[key];
}
return getTarget(obj[key], parts.slice(1).join('.'));
}
function getValue(dataPath, target) {
return getTarget(target || this, dataPath);
}
function getClass(dynamicClass, staticClass) {
return renderClass(staticClass, dynamicClass);
}
function getStyle(dynamicStyle, staticStyle) {
if (!dynamicStyle && !staticStyle) {
return '';
}
var dynamicStyleObj = normalizeStyleBinding(dynamicStyle);
var styleObj = staticStyle
? extend(staticStyle, dynamicStyleObj)
: dynamicStyleObj;
return Object.keys(styleObj)
.map(function (name) {
return hyphenate(name) + ':' + styleObj[name];
})
.join(';');
}
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
function normalizeStyleBinding(bindingStyle) {
if (Array.isArray(bindingStyle)) {
return toObject(bindingStyle);
}
if (typeof bindingStyle === 'string') {
return parseStyleText(bindingStyle);
}
return bindingStyle;
}
var parseStyleText = cache(function parseStyleText(cssText) {
var res = {};
var listDelimiter = /;(?![^(]*\))/g;
var propertyDelimiter = /:(.+)/;
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
var tmp = item.split(propertyDelimiter);
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
}
});
return res;
});
function isDef(v) {
return v !== undefined && v !== null;
}
function renderClass(staticClass, dynamicClass) {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass));
}
/* istanbul ignore next */
return '';
}
function concat(a, b) {
return a ? (b ? a + ' ' + b : a) : b || '';
}
function stringifyClass(value) {
if (Array.isArray(value)) {
return stringifyArray(value);
}
if (isObject(value)) {
return stringifyObject(value);
}
if (typeof value === 'string') {
return value;
}
/* istanbul ignore next */
return '';
}
function stringifyArray(value) {
var res = '';
var stringified;
for (var i = 0, l = value.length; i < l; i++) {
if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') {
if (res) {
res += ' ';
}
res += stringified;
}
}
return res;
}
function stringifyObject(value) {
var res = '';
for (var key in value) {
if (value[key]) {
if (res) {
res += ' ';
}
res += key;
}
}
return res;
}
function setModel(target, key, value, modifiers) {
if (isArray(modifiers)) {
if (modifiers.indexOf('trim') !== -1) {
......@@ -229,7 +433,9 @@ function initComponentInstance(instance, options) {
ctx.__set_sync = setSync;
ctx.__get_orig = getOrig;
// TODO
// ctx.__get_style = getStyle
ctx.__get_value = getValue;
ctx.__get_class = getClass;
ctx.__get_style = getStyle;
ctx.__map = map;
}
function initMocks(instance, mpInstance, mocks) {
......@@ -356,85 +562,6 @@ function initCreateApp(parseAppOptions) {
};
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
function createObserver(name) {
return function observer(newVal) {
......@@ -602,18 +729,6 @@ function applyOptions(componentOptions, vueOptions, initBehavior) {
componentOptions.behaviors = initBehaviors(vueOptions, initBehavior);
}
function getValue(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (parts.length === 1) {
return obj[key];
}
return getValue(obj[key], parts.slice(1).join('.'));
}
function getExtraValue(instance, dataPathsArray) {
let context = instance;
dataPathsArray.forEach((dataPathArray) => {
......@@ -635,7 +750,7 @@ function getExtraValue(instance, dataPathsArray) {
vFor = dataPath.substr(3);
}
else {
vFor = getValue(context, dataPath);
vFor = getTarget(context, dataPath);
}
}
if (Number.isInteger(vFor)) {
......@@ -647,12 +762,12 @@ function getExtraValue(instance, dataPathsArray) {
else {
if (isArray(vFor)) {
context = vFor.find((vForItem) => {
return getValue(vForItem, propPath) === value;
return getTarget(vForItem, propPath) === value;
});
}
else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find((vForKey) => {
return getValue(vFor[vForKey], propPath) === value;
return getTarget(vFor[vForKey], propPath) === value;
});
}
else {
......@@ -660,7 +775,7 @@ function getExtraValue(instance, dataPathsArray) {
}
}
if (valuePath) {
context = getValue(context, valuePath);
context = getTarget(context, valuePath);
}
}
});
......@@ -701,10 +816,10 @@ function processEventExtra(instance, extra, event) {
}
else if (dataPath.indexOf('$event.') === 0) {
// $event.target.value
extraObj['$' + index] = getValue(event, dataPath.replace('$event.', ''));
extraObj['$' + index] = getTarget(event, dataPath.replace('$event.', ''));
}
else {
extraObj['$' + index] = getValue(instance, dataPath);
extraObj['$' + index] = getTarget(instance, dataPath);
}
}
}
......@@ -849,7 +964,14 @@ function handleEvent(event) {
}
handler.once = true;
}
ret.push(handler.apply(handlerCtx, processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName)));
let params = processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName);
params = Array.isArray(params) ? params : [];
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) {
// eslint-disable-next-line no-sparse-arrays
params = params.concat([, , , , , , , , , , event]);
}
ret.push(handler.apply(handlerCtx, params));
}
});
}
......
......@@ -5,13 +5,26 @@ import {
addInterceptor,
removeInterceptor,
} from '@dcloudio/uni-api/src/service/base/interceptor'
import {
$on,
$off,
$once,
$emit,
} from '@dcloudio/uni-api/src/service/base/eventBus'
import { promisify } from './promise'
import { initWrapper } from './wrapper'
import { MPProtocols } from './protocols'
const baseApis = { upx2px, addInterceptor, removeInterceptor }
const baseApis = {
$on,
$off,
$once,
$emit,
upx2px,
addInterceptor,
removeInterceptor,
}
export function initUni(api: Record<string, any>, protocols: MPProtocols) {
const wrapper = initWrapper(protocols)
......
......@@ -8,6 +8,7 @@ import {
} from '@vue/shared'
import { ComponentPublicInstance } from 'vue'
import { MPComponentInstance } from './component'
import { getTarget } from './util'
interface Event extends WechatMiniprogram.BaseEvent {
detail: Record<string, any>
......@@ -15,19 +16,6 @@ interface Event extends WechatMiniprogram.BaseEvent {
preventDefault: () => void
}
function getValue(obj: any, path: string): unknown {
const parts = path.split('.')
let key: string | number = parts[0]
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''))
}
if (parts.length === 1) {
return obj[key]
}
return getValue(obj[key], parts.slice(1).join('.'))
}
function getExtraValue(
instance: ComponentPublicInstance,
dataPathsArray: string[]
......@@ -50,7 +38,7 @@ function getExtraValue(
if (dataPath.indexOf('#s#') === 0) {
vFor = dataPath.substr(3)
} else {
vFor = getValue(context, dataPath)
vFor = getTarget(context, dataPath)
}
}
......@@ -61,11 +49,11 @@ function getExtraValue(
} else {
if (isArray(vFor)) {
context = vFor.find((vForItem) => {
return getValue(vForItem, propPath) === value
return getTarget(vForItem, propPath) === value
})
} else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find((vForKey) => {
return getValue(vFor[vForKey], propPath) === value
return getTarget(vFor[vForKey], propPath) === value
})
} else {
console.error('v-for 暂不支持循环数据:', vFor)
......@@ -73,7 +61,7 @@ function getExtraValue(
}
if (valuePath) {
context = getValue(context, valuePath)
context = getTarget(context, valuePath)
}
}
})
......@@ -116,12 +104,12 @@ function processEventExtra(
}
} else if (dataPath.indexOf('$event.') === 0) {
// $event.target.value
extraObj['$' + index] = getValue(
extraObj['$' + index] = getTarget(
event,
dataPath.replace('$event.', '')
)
} else {
extraObj['$' + index] = getValue(instance, dataPath)
extraObj['$' + index] = getTarget(instance, dataPath)
}
}
} else {
......@@ -305,19 +293,25 @@ export function handleEvent(this: MPComponentInstance, event: Event) {
}
handler.once = true
}
ret.push(
handler.apply(
handlerCtx,
processEventArgs(
this.$vm!,
event,
eventArray[1],
eventArray[2],
isCustom,
methodName
)
)
let params = processEventArgs(
this.$vm!,
event,
eventArray[1],
eventArray[2],
isCustom,
methodName
)
params = Array.isArray(params) ? params : []
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
if (
/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(
handler.toString()
)
) {
// eslint-disable-next-line no-sparse-arrays
params = params.concat([, , , , , , , , , , event])
}
ret.push(handler.apply(handlerCtx, params))
}
})
}
......
......@@ -9,8 +9,9 @@ import {
} from '@vue/shared'
import { ComponentPublicInstance, ComponentInternalInstance } from 'vue'
import { getEventChannel } from '../api/protocols/navigateTo'
import { MPComponentInstance } from '../index'
import { getEventChannel } from '../../api/protocols/navigateTo'
import { MPComponentInstance } from '../component'
import { getClass, getStyle, getValue } from './utils'
function setModel(
this: ComponentPublicInstance,
......@@ -185,7 +186,9 @@ export function initComponentInstance(
ctx.__set_sync = setSync
ctx.__get_orig = getOrig
// TODO
// ctx.__get_style = getStyle
ctx.__get_value = getValue
ctx.__get_class = getClass
ctx.__get_style = getStyle
ctx.__map = map
}
......
import { ComponentPublicInstance } from 'vue'
import { extend, isObject, hyphenate } from '@vue/shared'
import { cache } from '@dcloudio/uni-shared'
import { getTarget } from '../util'
export function getValue(
this: ComponentPublicInstance,
dataPath: string,
target: Record<string, any>
) {
return getTarget(target || this, dataPath)
}
export function getClass(dynamicClass: unknown, staticClass: string) {
return renderClass(staticClass, dynamicClass)
}
export function getStyle(dynamicStyle: unknown, staticStyle: string) {
if (!dynamicStyle && !staticStyle) {
return ''
}
var dynamicStyleObj = normalizeStyleBinding(dynamicStyle)
var styleObj = staticStyle
? extend(staticStyle, dynamicStyleObj)
: dynamicStyleObj
return Object.keys(styleObj as any)
.map(function (name) {
return hyphenate(name) + ':' + (styleObj as any)[name]
})
.join(';')
}
function toObject(arr: unknown[]) {
var res = {}
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i])
}
}
return res
}
function normalizeStyleBinding(bindingStyle: unknown) {
if (Array.isArray(bindingStyle)) {
return toObject(bindingStyle)
}
if (typeof bindingStyle === 'string') {
return parseStyleText(bindingStyle)
}
return bindingStyle
}
var parseStyleText = cache(function parseStyleText(cssText) {
var res = {}
var listDelimiter = /;(?![^(]*\))/g
var propertyDelimiter = /:(.+)/
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
var tmp = item.split(propertyDelimiter)
tmp.length > 1 && ((res as any)[tmp[0].trim()] = tmp[1].trim())
}
})
return res
})
function isDef(v: unknown) {
return v !== undefined && v !== null
}
function renderClass(staticClass: string, dynamicClass: unknown) {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass))
}
/* istanbul ignore next */
return ''
}
function concat(a?: string, b?: string) {
return a ? (b ? a + ' ' + b : a) : b || ''
}
function stringifyClass(value: unknown) {
if (Array.isArray(value)) {
return stringifyArray(value)
}
if (isObject(value)) {
return stringifyObject(value)
}
if (typeof value === 'string') {
return value
}
/* istanbul ignore next */
return ''
}
function stringifyArray(value: unknown[]) {
var res = ''
var stringified
for (var i = 0, l = value.length; i < l; i++) {
if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') {
if (res) {
res += ' '
}
res += stringified
}
}
return res
}
function stringifyObject(value: Record<string, any>) {
var res = ''
for (var key in value) {
if (value[key]) {
if (res) {
res += ' '
}
res += key
}
}
return res
}
......@@ -124,3 +124,19 @@ export function findVmByVueId(
}
}
}
export function getTarget(obj: any, path: string): unknown {
const parts = path.split('.')
let key: number | string = parts[0]
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''))
}
if (!obj) {
obj = {}
}
if (parts.length === 1) {
return obj[key]
}
return getTarget(obj[key], parts.slice(1).join('.'))
}
......@@ -462,6 +462,114 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
}
}, RemoveInterceptorProtocol);
const API_ON = '$on';
const OnProtocol = [
{
name: 'event',
type: String,
required: true,
},
{
name: 'callback',
type: Function,
required: true,
},
];
const API_ONCE = '$once';
const OnceProtocol = OnProtocol;
const API_OFF = '$off';
const OffProtocol = [
{
name: 'event',
type: [String, Array],
},
{
name: 'callback',
type: Function,
},
];
const API_EMIT = '$emit';
const EmitProtocol = [
{
name: 'event',
type: String,
required: true,
},
];
const E = function () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
};
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx,
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener() {
self.off(name, listener);
callback.apply(ctx, arguments);
}
listener._ = callback;
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
liveEvents.length ? (e[name] = liveEvents) : delete e[name];
return this;
},
};
var Emitter = E;
const emitter = new Emitter();
const $on = defineSyncApi(API_ON, (name, callback) => {
emitter.on(name, callback);
return () => emitter.off(name, callback);
}, OnProtocol);
const $once = defineSyncApi(API_ONCE, (name, callback) => {
emitter.once(name, callback);
return () => emitter.off(name, callback);
}, OnceProtocol);
const $off = defineSyncApi(API_OFF, (name, callback) => {
if (!name) {
emitter.e = {};
return;
}
if (!Array.isArray(name))
name = [name];
name.forEach((n) => emitter.off(n, callback));
}, OffProtocol);
const $emit = defineSyncApi(API_EMIT, (name, ...args) => {
emitter.emit(name, ...args);
}, EmitProtocol);
const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/;
const CONTEXT_API_RE = /^create|Manager$/;
// Context例外情况
......@@ -606,7 +714,15 @@ function initWrapper(protocols) {
};
}
const baseApis = { upx2px, addInterceptor, removeInterceptor };
const baseApis = {
$on,
$off,
$once,
$emit,
upx2px,
addInterceptor,
removeInterceptor,
};
function initUni(api, protocols) {
const wrapper = initWrapper(protocols);
const UniProxyHandlers = {
......
import { isPlainObject, isArray, hasOwn, toNumber, isObject, isFunction, extend, NOOP, camelize } from '@vue/shared';
import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared';
const encode = encodeURIComponent;
function stringifyQuery(obj, encodeStr = encode) {
......@@ -19,6 +19,14 @@ function stringifyQuery(obj, encodeStr = encode) {
: null;
return res ? `?${res}` : '';
}
function cache(fn) {
const cache = Object.create(null);
return (str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
const invokeArrayFns = (fns, arg) => {
let ret;
for (let i = 0; i < fns.length; i++) {
......@@ -120,6 +128,202 @@ function getEventChannel(id) {
return eventChannelStack.shift();
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
function getTarget(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (!obj) {
obj = {};
}
if (parts.length === 1) {
return obj[key];
}
return getTarget(obj[key], parts.slice(1).join('.'));
}
function getValue(dataPath, target) {
return getTarget(target || this, dataPath);
}
function getClass(dynamicClass, staticClass) {
return renderClass(staticClass, dynamicClass);
}
function getStyle(dynamicStyle, staticStyle) {
if (!dynamicStyle && !staticStyle) {
return '';
}
var dynamicStyleObj = normalizeStyleBinding(dynamicStyle);
var styleObj = staticStyle
? extend(staticStyle, dynamicStyleObj)
: dynamicStyleObj;
return Object.keys(styleObj)
.map(function (name) {
return hyphenate(name) + ':' + styleObj[name];
})
.join(';');
}
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
function normalizeStyleBinding(bindingStyle) {
if (Array.isArray(bindingStyle)) {
return toObject(bindingStyle);
}
if (typeof bindingStyle === 'string') {
return parseStyleText(bindingStyle);
}
return bindingStyle;
}
var parseStyleText = cache(function parseStyleText(cssText) {
var res = {};
var listDelimiter = /;(?![^(]*\))/g;
var propertyDelimiter = /:(.+)/;
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
var tmp = item.split(propertyDelimiter);
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
}
});
return res;
});
function isDef(v) {
return v !== undefined && v !== null;
}
function renderClass(staticClass, dynamicClass) {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass));
}
/* istanbul ignore next */
return '';
}
function concat(a, b) {
return a ? (b ? a + ' ' + b : a) : b || '';
}
function stringifyClass(value) {
if (Array.isArray(value)) {
return stringifyArray(value);
}
if (isObject(value)) {
return stringifyObject(value);
}
if (typeof value === 'string') {
return value;
}
/* istanbul ignore next */
return '';
}
function stringifyArray(value) {
var res = '';
var stringified;
for (var i = 0, l = value.length; i < l; i++) {
if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') {
if (res) {
res += ' ';
}
res += stringified;
}
}
return res;
}
function stringifyObject(value) {
var res = '';
for (var key in value) {
if (value[key]) {
if (res) {
res += ' ';
}
res += key;
}
}
return res;
}
function setModel(target, key, value, modifiers) {
if (isArray(modifiers)) {
if (modifiers.indexOf('trim') !== -1) {
......@@ -229,7 +433,9 @@ function initComponentInstance(instance, options) {
ctx.__set_sync = setSync;
ctx.__get_orig = getOrig;
// TODO
// ctx.__get_style = getStyle
ctx.__get_value = getValue;
ctx.__get_class = getClass;
ctx.__get_style = getStyle;
ctx.__map = map;
}
function initMocks(instance, mpInstance, mocks) {
......@@ -356,85 +562,6 @@ function initCreateApp(parseAppOptions) {
};
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
function createObserver(name) {
return function observer(newVal) {
......@@ -591,18 +718,6 @@ function applyOptions(componentOptions, vueOptions, initBehavior) {
componentOptions.behaviors = initBehaviors(vueOptions, initBehavior);
}
function getValue(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (parts.length === 1) {
return obj[key];
}
return getValue(obj[key], parts.slice(1).join('.'));
}
function getExtraValue(instance, dataPathsArray) {
let context = instance;
dataPathsArray.forEach((dataPathArray) => {
......@@ -624,7 +739,7 @@ function getExtraValue(instance, dataPathsArray) {
vFor = dataPath.substr(3);
}
else {
vFor = getValue(context, dataPath);
vFor = getTarget(context, dataPath);
}
}
if (Number.isInteger(vFor)) {
......@@ -636,12 +751,12 @@ function getExtraValue(instance, dataPathsArray) {
else {
if (isArray(vFor)) {
context = vFor.find((vForItem) => {
return getValue(vForItem, propPath) === value;
return getTarget(vForItem, propPath) === value;
});
}
else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find((vForKey) => {
return getValue(vFor[vForKey], propPath) === value;
return getTarget(vFor[vForKey], propPath) === value;
});
}
else {
......@@ -649,7 +764,7 @@ function getExtraValue(instance, dataPathsArray) {
}
}
if (valuePath) {
context = getValue(context, valuePath);
context = getTarget(context, valuePath);
}
}
});
......@@ -690,10 +805,10 @@ function processEventExtra(instance, extra, event) {
}
else if (dataPath.indexOf('$event.') === 0) {
// $event.target.value
extraObj['$' + index] = getValue(event, dataPath.replace('$event.', ''));
extraObj['$' + index] = getTarget(event, dataPath.replace('$event.', ''));
}
else {
extraObj['$' + index] = getValue(instance, dataPath);
extraObj['$' + index] = getTarget(instance, dataPath);
}
}
}
......@@ -830,7 +945,14 @@ function handleEvent(event) {
}
handler.once = true;
}
ret.push(handler.apply(handlerCtx, processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName)));
let params = processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName);
params = Array.isArray(params) ? params : [];
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) {
// eslint-disable-next-line no-sparse-arrays
params = params.concat([, , , , , , , , , , event]);
}
ret.push(handler.apply(handlerCtx, params));
}
});
}
......
......@@ -462,6 +462,114 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
}
}, RemoveInterceptorProtocol);
const API_ON = '$on';
const OnProtocol = [
{
name: 'event',
type: String,
required: true,
},
{
name: 'callback',
type: Function,
required: true,
},
];
const API_ONCE = '$once';
const OnceProtocol = OnProtocol;
const API_OFF = '$off';
const OffProtocol = [
{
name: 'event',
type: [String, Array],
},
{
name: 'callback',
type: Function,
},
];
const API_EMIT = '$emit';
const EmitProtocol = [
{
name: 'event',
type: String,
required: true,
},
];
const E = function () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
};
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx,
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener() {
self.off(name, listener);
callback.apply(ctx, arguments);
}
listener._ = callback;
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
liveEvents.length ? (e[name] = liveEvents) : delete e[name];
return this;
},
};
var Emitter = E;
const emitter = new Emitter();
const $on = defineSyncApi(API_ON, (name, callback) => {
emitter.on(name, callback);
return () => emitter.off(name, callback);
}, OnProtocol);
const $once = defineSyncApi(API_ONCE, (name, callback) => {
emitter.once(name, callback);
return () => emitter.off(name, callback);
}, OnceProtocol);
const $off = defineSyncApi(API_OFF, (name, callback) => {
if (!name) {
emitter.e = {};
return;
}
if (!Array.isArray(name))
name = [name];
name.forEach((n) => emitter.off(n, callback));
}, OffProtocol);
const $emit = defineSyncApi(API_EMIT, (name, ...args) => {
emitter.emit(name, ...args);
}, EmitProtocol);
const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/;
const CONTEXT_API_RE = /^create|Manager$/;
// Context例外情况
......@@ -606,7 +714,15 @@ function initWrapper(protocols) {
};
}
const baseApis = { upx2px, addInterceptor, removeInterceptor };
const baseApis = {
$on,
$off,
$once,
$emit,
upx2px,
addInterceptor,
removeInterceptor,
};
function initUni(api, protocols) {
const wrapper = initWrapper(protocols);
const UniProxyHandlers = {
......
import { isPlainObject, isArray, hasOwn, toNumber, isObject, isFunction, extend, NOOP, camelize } from '@vue/shared';
import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared';
const encode = encodeURIComponent;
function stringifyQuery(obj, encodeStr = encode) {
......@@ -19,6 +19,14 @@ function stringifyQuery(obj, encodeStr = encode) {
: null;
return res ? `?${res}` : '';
}
function cache(fn) {
const cache = Object.create(null);
return (str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
const invokeArrayFns = (fns, arg) => {
let ret;
for (let i = 0; i < fns.length; i++) {
......@@ -120,6 +128,202 @@ function getEventChannel(id) {
return eventChannelStack.shift();
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
function getTarget(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (!obj) {
obj = {};
}
if (parts.length === 1) {
return obj[key];
}
return getTarget(obj[key], parts.slice(1).join('.'));
}
function getValue(dataPath, target) {
return getTarget(target || this, dataPath);
}
function getClass(dynamicClass, staticClass) {
return renderClass(staticClass, dynamicClass);
}
function getStyle(dynamicStyle, staticStyle) {
if (!dynamicStyle && !staticStyle) {
return '';
}
var dynamicStyleObj = normalizeStyleBinding(dynamicStyle);
var styleObj = staticStyle
? extend(staticStyle, dynamicStyleObj)
: dynamicStyleObj;
return Object.keys(styleObj)
.map(function (name) {
return hyphenate(name) + ':' + styleObj[name];
})
.join(';');
}
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
function normalizeStyleBinding(bindingStyle) {
if (Array.isArray(bindingStyle)) {
return toObject(bindingStyle);
}
if (typeof bindingStyle === 'string') {
return parseStyleText(bindingStyle);
}
return bindingStyle;
}
var parseStyleText = cache(function parseStyleText(cssText) {
var res = {};
var listDelimiter = /;(?![^(]*\))/g;
var propertyDelimiter = /:(.+)/;
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
var tmp = item.split(propertyDelimiter);
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
}
});
return res;
});
function isDef(v) {
return v !== undefined && v !== null;
}
function renderClass(staticClass, dynamicClass) {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass));
}
/* istanbul ignore next */
return '';
}
function concat(a, b) {
return a ? (b ? a + ' ' + b : a) : b || '';
}
function stringifyClass(value) {
if (Array.isArray(value)) {
return stringifyArray(value);
}
if (isObject(value)) {
return stringifyObject(value);
}
if (typeof value === 'string') {
return value;
}
/* istanbul ignore next */
return '';
}
function stringifyArray(value) {
var res = '';
var stringified;
for (var i = 0, l = value.length; i < l; i++) {
if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') {
if (res) {
res += ' ';
}
res += stringified;
}
}
return res;
}
function stringifyObject(value) {
var res = '';
for (var key in value) {
if (value[key]) {
if (res) {
res += ' ';
}
res += key;
}
}
return res;
}
function setModel(target, key, value, modifiers) {
if (isArray(modifiers)) {
if (modifiers.indexOf('trim') !== -1) {
......@@ -229,7 +433,9 @@ function initComponentInstance(instance, options) {
ctx.__set_sync = setSync;
ctx.__get_orig = getOrig;
// TODO
// ctx.__get_style = getStyle
ctx.__get_value = getValue;
ctx.__get_class = getClass;
ctx.__get_style = getStyle;
ctx.__map = map;
}
function initMocks(instance, mpInstance, mocks) {
......@@ -359,85 +565,6 @@ function initCreateApp(parseAppOptions) {
};
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
function createObserver(name) {
return function observer(newVal) {
......@@ -600,18 +727,6 @@ function applyOptions(componentOptions, vueOptions, initBehavior) {
componentOptions.behaviors = initBehaviors(vueOptions, initBehavior);
}
function getValue(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (parts.length === 1) {
return obj[key];
}
return getValue(obj[key], parts.slice(1).join('.'));
}
function getExtraValue(instance, dataPathsArray) {
let context = instance;
dataPathsArray.forEach((dataPathArray) => {
......@@ -633,7 +748,7 @@ function getExtraValue(instance, dataPathsArray) {
vFor = dataPath.substr(3);
}
else {
vFor = getValue(context, dataPath);
vFor = getTarget(context, dataPath);
}
}
if (Number.isInteger(vFor)) {
......@@ -645,12 +760,12 @@ function getExtraValue(instance, dataPathsArray) {
else {
if (isArray(vFor)) {
context = vFor.find((vForItem) => {
return getValue(vForItem, propPath) === value;
return getTarget(vForItem, propPath) === value;
});
}
else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find((vForKey) => {
return getValue(vFor[vForKey], propPath) === value;
return getTarget(vFor[vForKey], propPath) === value;
});
}
else {
......@@ -658,7 +773,7 @@ function getExtraValue(instance, dataPathsArray) {
}
}
if (valuePath) {
context = getValue(context, valuePath);
context = getTarget(context, valuePath);
}
}
});
......@@ -699,10 +814,10 @@ function processEventExtra(instance, extra, event) {
}
else if (dataPath.indexOf('$event.') === 0) {
// $event.target.value
extraObj['$' + index] = getValue(event, dataPath.replace('$event.', ''));
extraObj['$' + index] = getTarget(event, dataPath.replace('$event.', ''));
}
else {
extraObj['$' + index] = getValue(instance, dataPath);
extraObj['$' + index] = getTarget(instance, dataPath);
}
}
}
......@@ -839,7 +954,14 @@ function handleEvent(event) {
}
handler.once = true;
}
ret.push(handler.apply(handlerCtx, processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName)));
let params = processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName);
params = Array.isArray(params) ? params : [];
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) {
// eslint-disable-next-line no-sparse-arrays
params = params.concat([, , , , , , , , , , event]);
}
ret.push(handler.apply(handlerCtx, params));
}
});
}
......
......@@ -426,6 +426,114 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
}
}, RemoveInterceptorProtocol);
const API_ON = '$on';
const OnProtocol = [
{
name: 'event',
type: String,
required: true,
},
{
name: 'callback',
type: Function,
required: true,
},
];
const API_ONCE = '$once';
const OnceProtocol = OnProtocol;
const API_OFF = '$off';
const OffProtocol = [
{
name: 'event',
type: [String, Array],
},
{
name: 'callback',
type: Function,
},
];
const API_EMIT = '$emit';
const EmitProtocol = [
{
name: 'event',
type: String,
required: true,
},
];
const E = function () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
};
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx,
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener() {
self.off(name, listener);
callback.apply(ctx, arguments);
}
listener._ = callback;
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
liveEvents.length ? (e[name] = liveEvents) : delete e[name];
return this;
},
};
var Emitter = E;
const emitter = new Emitter();
const $on = defineSyncApi(API_ON, (name, callback) => {
emitter.on(name, callback);
return () => emitter.off(name, callback);
}, OnProtocol);
const $once = defineSyncApi(API_ONCE, (name, callback) => {
emitter.once(name, callback);
return () => emitter.off(name, callback);
}, OnceProtocol);
const $off = defineSyncApi(API_OFF, (name, callback) => {
if (!name) {
emitter.e = {};
return;
}
if (!Array.isArray(name))
name = [name];
name.forEach((n) => emitter.off(n, callback));
}, OffProtocol);
const $emit = defineSyncApi(API_EMIT, (name, ...args) => {
emitter.emit(name, ...args);
}, EmitProtocol);
const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/;
const CONTEXT_API_RE = /^create|Manager$/;
// Context例外情况
......@@ -570,7 +678,15 @@ function initWrapper(protocols) {
};
}
const baseApis = { upx2px, addInterceptor, removeInterceptor };
const baseApis = {
$on,
$off,
$once,
$emit,
upx2px,
addInterceptor,
removeInterceptor,
};
function initUni(api, protocols) {
const wrapper = initWrapper(protocols);
const UniProxyHandlers = {
......
import { isPlainObject, isArray, hasOwn, toNumber, isObject, isFunction, extend, NOOP, camelize } from '@vue/shared';
import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared';
const encode = encodeURIComponent;
function stringifyQuery(obj, encodeStr = encode) {
......@@ -19,6 +19,14 @@ function stringifyQuery(obj, encodeStr = encode) {
: null;
return res ? `?${res}` : '';
}
function cache(fn) {
const cache = Object.create(null);
return (str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
const invokeArrayFns = (fns, arg) => {
let ret;
for (let i = 0; i < fns.length; i++) {
......@@ -57,6 +65,211 @@ function getEventChannel(id) {
return eventChannelStack.shift();
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
{
if (component.dataset.vueGeneric === 'scoped') {
component
.selectAllComponents('.scoped-ref')
.forEach((scopedComponent) => {
selectAllComponents(scopedComponent, selector, $refs);
});
}
}
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
function getTarget(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (!obj) {
obj = {};
}
if (parts.length === 1) {
return obj[key];
}
return getTarget(obj[key], parts.slice(1).join('.'));
}
function getValue(dataPath, target) {
return getTarget(target || this, dataPath);
}
function getClass(dynamicClass, staticClass) {
return renderClass(staticClass, dynamicClass);
}
function getStyle(dynamicStyle, staticStyle) {
if (!dynamicStyle && !staticStyle) {
return '';
}
var dynamicStyleObj = normalizeStyleBinding(dynamicStyle);
var styleObj = staticStyle
? extend(staticStyle, dynamicStyleObj)
: dynamicStyleObj;
return Object.keys(styleObj)
.map(function (name) {
return hyphenate(name) + ':' + styleObj[name];
})
.join(';');
}
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
function normalizeStyleBinding(bindingStyle) {
if (Array.isArray(bindingStyle)) {
return toObject(bindingStyle);
}
if (typeof bindingStyle === 'string') {
return parseStyleText(bindingStyle);
}
return bindingStyle;
}
var parseStyleText = cache(function parseStyleText(cssText) {
var res = {};
var listDelimiter = /;(?![^(]*\))/g;
var propertyDelimiter = /:(.+)/;
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
var tmp = item.split(propertyDelimiter);
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
}
});
return res;
});
function isDef(v) {
return v !== undefined && v !== null;
}
function renderClass(staticClass, dynamicClass) {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass));
}
/* istanbul ignore next */
return '';
}
function concat(a, b) {
return a ? (b ? a + ' ' + b : a) : b || '';
}
function stringifyClass(value) {
if (Array.isArray(value)) {
return stringifyArray(value);
}
if (isObject(value)) {
return stringifyObject(value);
}
if (typeof value === 'string') {
return value;
}
/* istanbul ignore next */
return '';
}
function stringifyArray(value) {
var res = '';
var stringified;
for (var i = 0, l = value.length; i < l; i++) {
if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') {
if (res) {
res += ' ';
}
res += stringified;
}
}
return res;
}
function stringifyObject(value) {
var res = '';
for (var key in value) {
if (value[key]) {
if (res) {
res += ' ';
}
res += key;
}
}
return res;
}
function setModel(target, key, value, modifiers) {
if (isArray(modifiers)) {
if (modifiers.indexOf('trim') !== -1) {
......@@ -166,7 +379,9 @@ function initComponentInstance(instance, options) {
ctx.__set_sync = setSync;
ctx.__get_orig = getOrig;
// TODO
// ctx.__get_style = getStyle
ctx.__get_value = getValue;
ctx.__get_class = getClass;
ctx.__get_style = getStyle;
ctx.__map = map;
}
function initMocks(instance, mpInstance, mocks) {
......@@ -293,94 +508,6 @@ function initCreateApp(parseAppOptions) {
};
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
{
if (component.dataset.vueGeneric === 'scoped') {
component
.selectAllComponents('.scoped-ref')
.forEach((scopedComponent) => {
selectAllComponents(scopedComponent, selector, $refs);
});
}
}
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function findVmByVueId(instance, vuePid) {
// 标准 vue3 中 没有 $children,定制了内核
const $children = instance.$children;
// 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
for (let i = $children.length - 1; i >= 0; i--) {
const childVm = $children[i];
if (childVm.$scope._$vueId === vuePid) {
return childVm;
}
}
// 反向递归查找
let parentVm;
for (let i = $children.length - 1; i >= 0; i--) {
parentVm = findVmByVueId($children[i], vuePid);
if (parentVm) {
return parentVm;
}
}
}
const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
function createObserver(name) {
return function observer(newVal) {
......@@ -537,18 +664,6 @@ function applyOptions(componentOptions, vueOptions, initBehavior) {
componentOptions.behaviors = initBehaviors(vueOptions, initBehavior);
}
function getValue(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (parts.length === 1) {
return obj[key];
}
return getValue(obj[key], parts.slice(1).join('.'));
}
function getExtraValue(instance, dataPathsArray) {
let context = instance;
dataPathsArray.forEach((dataPathArray) => {
......@@ -570,7 +685,7 @@ function getExtraValue(instance, dataPathsArray) {
vFor = dataPath.substr(3);
}
else {
vFor = getValue(context, dataPath);
vFor = getTarget(context, dataPath);
}
}
if (Number.isInteger(vFor)) {
......@@ -582,12 +697,12 @@ function getExtraValue(instance, dataPathsArray) {
else {
if (isArray(vFor)) {
context = vFor.find((vForItem) => {
return getValue(vForItem, propPath) === value;
return getTarget(vForItem, propPath) === value;
});
}
else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find((vForKey) => {
return getValue(vFor[vForKey], propPath) === value;
return getTarget(vFor[vForKey], propPath) === value;
});
}
else {
......@@ -595,7 +710,7 @@ function getExtraValue(instance, dataPathsArray) {
}
}
if (valuePath) {
context = getValue(context, valuePath);
context = getTarget(context, valuePath);
}
}
});
......@@ -636,10 +751,10 @@ function processEventExtra(instance, extra, event) {
}
else if (dataPath.indexOf('$event.') === 0) {
// $event.target.value
extraObj['$' + index] = getValue(event, dataPath.replace('$event.', ''));
extraObj['$' + index] = getTarget(event, dataPath.replace('$event.', ''));
}
else {
extraObj['$' + index] = getValue(instance, dataPath);
extraObj['$' + index] = getTarget(instance, dataPath);
}
}
}
......@@ -776,7 +891,14 @@ function handleEvent(event) {
}
handler.once = true;
}
ret.push(handler.apply(handlerCtx, processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName)));
let params = processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName);
params = Array.isArray(params) ? params : [];
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) {
// eslint-disable-next-line no-sparse-arrays
params = params.concat([, , , , , , , , , , event]);
}
ret.push(handler.apply(handlerCtx, params));
}
});
}
......
......@@ -462,6 +462,114 @@ const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interce
}
}, RemoveInterceptorProtocol);
const API_ON = '$on';
const OnProtocol = [
{
name: 'event',
type: String,
required: true,
},
{
name: 'callback',
type: Function,
required: true,
},
];
const API_ONCE = '$once';
const OnceProtocol = OnProtocol;
const API_OFF = '$off';
const OffProtocol = [
{
name: 'event',
type: [String, Array],
},
{
name: 'callback',
type: Function,
},
];
const API_EMIT = '$emit';
const EmitProtocol = [
{
name: 'event',
type: String,
required: true,
},
];
const E = function () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
};
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx,
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener() {
self.off(name, listener);
callback.apply(ctx, arguments);
}
listener._ = callback;
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
liveEvents.length ? (e[name] = liveEvents) : delete e[name];
return this;
},
};
var Emitter = E;
const emitter = new Emitter();
const $on = defineSyncApi(API_ON, (name, callback) => {
emitter.on(name, callback);
return () => emitter.off(name, callback);
}, OnProtocol);
const $once = defineSyncApi(API_ONCE, (name, callback) => {
emitter.once(name, callback);
return () => emitter.off(name, callback);
}, OnceProtocol);
const $off = defineSyncApi(API_OFF, (name, callback) => {
if (!name) {
emitter.e = {};
return;
}
if (!Array.isArray(name))
name = [name];
name.forEach((n) => emitter.off(n, callback));
}, OffProtocol);
const $emit = defineSyncApi(API_EMIT, (name, ...args) => {
emitter.emit(name, ...args);
}, EmitProtocol);
const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/;
const CONTEXT_API_RE = /^create|Manager$/;
// Context例外情况
......@@ -606,7 +714,15 @@ function initWrapper(protocols) {
};
}
const baseApis = { upx2px, addInterceptor, removeInterceptor };
const baseApis = {
$on,
$off,
$once,
$emit,
upx2px,
addInterceptor,
removeInterceptor,
};
function initUni(api, protocols) {
const wrapper = initWrapper(protocols);
const UniProxyHandlers = {
......
import { isPlainObject, isArray, hasOwn, toNumber, isObject, isFunction, extend, NOOP, camelize } from '@vue/shared';
import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared';
const encode = encodeURIComponent;
function stringifyQuery(obj, encodeStr = encode) {
......@@ -19,6 +19,14 @@ function stringifyQuery(obj, encodeStr = encode) {
: null;
return res ? `?${res}` : '';
}
function cache(fn) {
const cache = Object.create(null);
return (str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
const invokeArrayFns = (fns, arg) => {
let ret;
for (let i = 0; i < fns.length; i++) {
......@@ -120,6 +128,183 @@ function getEventChannel(id) {
return eventChannelStack.shift();
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
function getTarget(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (!obj) {
obj = {};
}
if (parts.length === 1) {
return obj[key];
}
return getTarget(obj[key], parts.slice(1).join('.'));
}
function getValue(dataPath, target) {
return getTarget(target || this, dataPath);
}
function getClass(dynamicClass, staticClass) {
return renderClass(staticClass, dynamicClass);
}
function getStyle(dynamicStyle, staticStyle) {
if (!dynamicStyle && !staticStyle) {
return '';
}
var dynamicStyleObj = normalizeStyleBinding(dynamicStyle);
var styleObj = staticStyle
? extend(staticStyle, dynamicStyleObj)
: dynamicStyleObj;
return Object.keys(styleObj)
.map(function (name) {
return hyphenate(name) + ':' + styleObj[name];
})
.join(';');
}
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
function normalizeStyleBinding(bindingStyle) {
if (Array.isArray(bindingStyle)) {
return toObject(bindingStyle);
}
if (typeof bindingStyle === 'string') {
return parseStyleText(bindingStyle);
}
return bindingStyle;
}
var parseStyleText = cache(function parseStyleText(cssText) {
var res = {};
var listDelimiter = /;(?![^(]*\))/g;
var propertyDelimiter = /:(.+)/;
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
var tmp = item.split(propertyDelimiter);
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
}
});
return res;
});
function isDef(v) {
return v !== undefined && v !== null;
}
function renderClass(staticClass, dynamicClass) {
if (isDef(staticClass) || isDef(dynamicClass)) {
return concat(staticClass, stringifyClass(dynamicClass));
}
/* istanbul ignore next */
return '';
}
function concat(a, b) {
return a ? (b ? a + ' ' + b : a) : b || '';
}
function stringifyClass(value) {
if (Array.isArray(value)) {
return stringifyArray(value);
}
if (isObject(value)) {
return stringifyObject(value);
}
if (typeof value === 'string') {
return value;
}
/* istanbul ignore next */
return '';
}
function stringifyArray(value) {
var res = '';
var stringified;
for (var i = 0, l = value.length; i < l; i++) {
if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') {
if (res) {
res += ' ';
}
res += stringified;
}
}
return res;
}
function stringifyObject(value) {
var res = '';
for (var key in value) {
if (value[key]) {
if (res) {
res += ' ';
}
res += key;
}
}
return res;
}
function setModel(target, key, value, modifiers) {
if (isArray(modifiers)) {
if (modifiers.indexOf('trim') !== -1) {
......@@ -229,7 +414,9 @@ function initComponentInstance(instance, options) {
ctx.__set_sync = setSync;
ctx.__get_orig = getOrig;
// TODO
// ctx.__get_style = getStyle
ctx.__get_value = getValue;
ctx.__get_class = getClass;
ctx.__get_style = getStyle;
ctx.__map = map;
}
function initMocks(instance, mpInstance, mocks) {
......@@ -356,66 +543,6 @@ function initCreateApp(parseAppOptions) {
};
}
function initBehavior(options) {
return Behavior(options);
}
function initVueIds(vueIds, mpInstance) {
if (!vueIds) {
return;
}
const ids = vueIds.split(',');
const len = ids.length;
if (len === 1) {
mpInstance._$vueId = ids[0];
}
else if (len === 2) {
mpInstance._$vueId = ids[0];
mpInstance._$vuePid = ids[1];
}
}
const EXTRAS = ['externalClasses'];
function initExtraOptions(miniProgramComponentOptions, vueOptions) {
EXTRAS.forEach((name) => {
if (hasOwn(vueOptions, name)) {
miniProgramComponentOptions[name] = vueOptions[name];
}
});
}
function initWxsCallMethods(methods, wxsCallMethods) {
if (!isArray(wxsCallMethods)) {
return;
}
wxsCallMethods.forEach((callMethod) => {
methods[callMethod] = function (args) {
return this.$vm[callMethod](args);
};
});
}
function selectAllComponents(mpInstance, selector, $refs) {
const components = mpInstance.selectAllComponents(selector);
components.forEach((component) => {
const ref = component.dataset.ref;
$refs[ref] = component.$vm || component;
});
}
function initRefs(instance, mpInstance) {
Object.defineProperty(instance, 'refs', {
get() {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
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 || component);
});
return $refs;
},
});
}
const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
function createObserver(name) {
return function observer(newVal) {
......@@ -572,18 +699,6 @@ function applyOptions(componentOptions, vueOptions, initBehavior) {
componentOptions.behaviors = initBehaviors(vueOptions, initBehavior);
}
function getValue(obj, path) {
const parts = path.split('.');
let key = parts[0];
if (key.indexOf('__$n') === 0) {
//number index
key = parseInt(key.replace('__$n', ''));
}
if (parts.length === 1) {
return obj[key];
}
return getValue(obj[key], parts.slice(1).join('.'));
}
function getExtraValue(instance, dataPathsArray) {
let context = instance;
dataPathsArray.forEach((dataPathArray) => {
......@@ -605,7 +720,7 @@ function getExtraValue(instance, dataPathsArray) {
vFor = dataPath.substr(3);
}
else {
vFor = getValue(context, dataPath);
vFor = getTarget(context, dataPath);
}
}
if (Number.isInteger(vFor)) {
......@@ -617,12 +732,12 @@ function getExtraValue(instance, dataPathsArray) {
else {
if (isArray(vFor)) {
context = vFor.find((vForItem) => {
return getValue(vForItem, propPath) === value;
return getTarget(vForItem, propPath) === value;
});
}
else if (isPlainObject(vFor)) {
context = Object.keys(vFor).find((vForKey) => {
return getValue(vFor[vForKey], propPath) === value;
return getTarget(vFor[vForKey], propPath) === value;
});
}
else {
......@@ -630,7 +745,7 @@ function getExtraValue(instance, dataPathsArray) {
}
}
if (valuePath) {
context = getValue(context, valuePath);
context = getTarget(context, valuePath);
}
}
});
......@@ -671,10 +786,10 @@ function processEventExtra(instance, extra, event) {
}
else if (dataPath.indexOf('$event.') === 0) {
// $event.target.value
extraObj['$' + index] = getValue(event, dataPath.replace('$event.', ''));
extraObj['$' + index] = getTarget(event, dataPath.replace('$event.', ''));
}
else {
extraObj['$' + index] = getValue(instance, dataPath);
extraObj['$' + index] = getTarget(instance, dataPath);
}
}
}
......@@ -811,7 +926,14 @@ function handleEvent(event) {
}
handler.once = true;
}
ret.push(handler.apply(handlerCtx, processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName)));
let params = processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName);
params = Array.isArray(params) ? params : [];
// 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) {
// eslint-disable-next-line no-sparse-arrays
params = params.concat([, , , , , , , , , , event]);
}
ret.push(handler.apply(handlerCtx, params));
}
});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册