fineui是帆软报表和BI产品线所使用的前端框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1460 lines
42 KiB

import { _ } from "@/core";
let uid = 0;
const pendingCleanupDeps = [];
const cleanupDeps = () => {
for (let i = 0; i < pendingCleanupDeps.length; i++) {
const dep = pendingCleanupDeps[i];
dep.subs = dep.subs.filter(s => dep.subsSet.has(s.id));
dep._pending = false;
}
pendingCleanupDeps.length = 0;
};
/**
* A dep is an observable that can have multiple
* directives subscribing to it.
*/
class Dep {
constructor() {
this.id = uid++;
this._pending = false;
this.subs = [];
this.subsSet = new Set();
}
addSub(sub) {
this.subs.push(sub);
this.subsSet.add(sub.id);
}
removeSub(sub) {
this.subsSet.delete(sub.id);
if (!this._pending) {
this._pending = true;
pendingCleanupDeps.push(this);
}
}
depend() {
if (Dep.target) {
Dep.target.addDep(this);
}
}
notify(options) {
// stabilize the subscriber list first
const subs = this.subs.filter(s => this.subsSet.has(s.id));
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update(options);
}
}
}
// the current target watcher being evaluated.
// this is globally unique because there could be only one
// watcher being evaluated at any time.
Dep.target = null;
const targetStack = [];
function pushTarget(_target) {
if (Dep.target) targetStack.push(Dep.target);
Dep.target = _target;
}
function popTarget() {
Dep.target = targetStack.pop();
}
function noop(a, b, c) {
}
function isNative(Ctor) {
return typeof Ctor === "function" && /native code/.test(Ctor.toString());
}
const hasProto = "__proto__" in {};
const _toString = Object.prototype.toString;
function isPlainObject(obj) {
return _toString.call(obj) === "[object Object]";
}
function isConfigurable(obj, key) {
let configurable = true;
const property = Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
configurable = false;
}
return configurable;
}
function isExtensible(obj) {
if (Object.isExtensible) {
return Object.isExtensible(obj);
}
let name = "";
while (obj.hasOwnProperty(name)) {
name += "?";
}
obj[name] = true;
let returnValue = obj.hasOwnProperty(name);
delete obj[name];
return returnValue;
}
function remove(arr, item) {
if (!arr) {
return;
}
const len = arr.length;
if (len) {
if (item === arr[len - 1]) {
arr.length = len - 1;
return;
}
const index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1);
}
}
}
// const bailRE = /[^\w.$]/
function parsePath(path) {
// 正常表达式比较慢,能不要的就不要了
// if (bailRE.test(path)) {
// return
// }
const segments = path.split(".");
return function (obj) {
for (let i = 0; i < segments.length; i++) {
if (!obj) return;
obj = obj[segments[i]];
}
return obj;
};
}
const nextTick = (function () {
const callbacks = [];
let pending = false;
let timerFunc;
function nextTickHandler() {
pending = false;
const copies = callbacks.slice(0);
callbacks.length = 0;
for (let i = 0; i < copies.length; i++) {
copies[i]();
}
}
// An asynchronous deferring mechanism.
// In pre 2.4, we used to use microtasks (Promise/MutationObserver)
// but microtasks actually has too high a priority and fires in between
// supposedly sequential events (e.g. #4521, #6690) or even between
// bubbling of the same event (#6566). Technically setImmediate should be
// the ideal choice, but it's not available everywhere; and the only polyfill
// that consistently queues the callback after all DOM events triggered in the
// same loop is by using MessageChannel.
/* istanbul ignore if */
if (typeof setImmediate !== "undefined" && isNative(setImmediate)) {
timerFunc = () => {
setImmediate(nextTickHandler);
};
} else if (typeof MessageChannel !== "undefined" && (
isNative(MessageChannel) ||
// PhantomJS
MessageChannel.toString() === "[object MessageChannelConstructor]"
)) {
const channel = new MessageChannel();
const port = channel.port2;
channel.port1.onmessage = nextTickHandler;
timerFunc = () => {
port.postMessage(1);
};
} else
/* istanbul ignore next */
if (typeof Promise !== "undefined" && isNative(Promise)) {
// use microtask in non-DOM environments, e.g. Weex
const p = Promise.resolve();
timerFunc = () => {
p.then(nextTickHandler);
};
} else {
// fallback to setTimeout
timerFunc = () => {
setTimeout(nextTickHandler, 0);
};
}
return function queueNextTick(cb, ctx) {
let _resolve;
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx);
} catch (e) {
console.error(e);
}
} else if (_resolve) {
_resolve(ctx);
}
});
if (!pending) {
pending = true;
timerFunc();
}
if (!cb && typeof Promise !== "undefined") {
return new Promise((resolve, reject) => {
_resolve = resolve;
});
}
};
})();
var falsy;
const $$skipArray = {
__ob__: falsy,
$accessors: falsy,
$vbthis: falsy,
$vbsetter: falsy
};
//如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
//标准浏览器使用__defineGetter__, __defineSetter__实现
let canHideProperty = true;
try {
Object.defineProperty({}, "_", {
value: "x"
});
delete $$skipArray.$vbsetter;
delete $$skipArray.$vbthis;
} catch (e) {
/* istanbul ignore next*/
canHideProperty = false;
}
let createViewModel = Object.defineProperties;
let defineProperty;
/* istanbul ignore if*/
if (!canHideProperty) {
if ("__defineGetter__" in {}) {
defineProperty = function (obj, prop, desc) {
if ("value" in desc) {
obj[prop] = desc.value;
}
if ("get" in desc) {
obj.__defineGetter__(prop, desc.get);
}
if ("set" in desc) {
obj.__defineSetter__(prop, desc.set);
}
return obj;
};
createViewModel = function (obj, descs) {
for (var prop in descs) {
if (descs.hasOwnProperty(prop)) {
defineProperty(obj, prop, descs[prop]);
}
}
return obj;
};
}
}
var createViewModel$1 = createViewModel;
const queue = [];
const activatedChildren = [];
let has = {};
let waiting = false;
let flushing = false;
let index = 0;
function resetSchedulerState() {
index = queue.length = activatedChildren.length = 0;
has = {};
waiting = flushing = false;
}
function flushSchedulerQueue() {
flushing = true;
let watcher, id, options;
// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
queue.sort((a, b) => a.id - b.id);
// do not cache length because more watchers might be pushed
// as we run existing watchers
for (index = 0; index < queue.length; index++) {
watcher = queue[index].watcher;
options = queue[index].options;
id = watcher.id;
has[id] = null;
watcher.run(options);
}
resetSchedulerState();
cleanupDeps();
}
function queueWatcher(watcher, options) {
const id = watcher.id;
if (has[id] == null) {
has[id] = true;
if (!flushing) {
queue.push({ watcher: watcher, options: options });
} else {
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
let i = queue.length - 1;
while (i > index && queue[i].watcher.id > watcher.id) {
i--;
}
queue.splice(i + 1, 0, { watcher: watcher, options: options });
}
// queue the flush
if (!waiting) {
waiting = true;
nextTick(flushSchedulerQueue);
}
}
}
let uid$1 = 0;
class Watcher {
constructor(vm,
expOrFn,
cb,
options) {
this.vm = vm;
// vm._watchers || (vm._watchers = [])
// vm._watchers.push(this)
// options
if (options) {
this.deep = !!options.deep;
this.user = !!options.user;
this.lazy = !!options.lazy;
this.sync = !!options.sync;
} else {
this.deep = this.user = this.lazy = this.sync = false;
}
this.cb = cb;
this.id = ++uid$1; // uid for batching
this.active = true;
this.dirty = this.lazy; // for lazy watchers
this.deps = [];
this.newDeps = [];
this.depIds = new Set();
this.newDepIds = new Set();
this.expression = "";
// parse expression for getter
if (typeof expOrFn === "function") {
this.getter = expOrFn;
} else {
this.getter = parsePath(expOrFn);
if (!this.getter) {
this.getter = function () {
};
}
}
this.value = this.lazy
? undefined
: this.get();
}
get() {
pushTarget(this);
let value;
const vm = this.vm;
try {
value = this.getter.call(vm, vm);
} catch (e) {
// if (this.user) {
// } else {
// console.error(e)
// }
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value);
}
popTarget();
this.cleanupDeps();
}
return value;
}
addDep(dep) {
const id = dep.id;
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id);
this.newDeps.push(dep);
if (!this.depIds.has(id)) {
dep.addSub(this);
}
}
}
cleanupDeps() {
let i = this.deps.length;
while (i--) {
const dep = this.deps[i];
if (!this.newDepIds.has(dep.id)) {
dep.removeSub(this);
}
}
let tmp = this.depIds;
this.depIds = this.newDepIds;
this.newDepIds = tmp;
this.newDepIds.clear();
tmp = this.deps;
this.deps = this.newDeps;
this.newDeps = tmp;
this.newDeps.length = 0;
}
update(options) {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true;
} else if (this.sync) {
this.run(options);
} else {
queueWatcher(this, options);
}
}
run(options) {
if (this.active) {
const value = this.get();
if (
value !== this.value ||
// Deep watchers and watchers on Object/Arrays should fire even
// when the value is the same, because the value may
// have mutated.
(_.isObject(value) && options && options.refresh) || this.deep
) {
// set new value
const oldValue = this.value;
this.value = value;
if (this.user) {
try {
this.cb.call(this.vm, value, oldValue, options);
} catch (e) {
console.error(e);
}
} else {
try {
this.cb.call(this.vm, value, oldValue, options);
} catch (e) {
console.error(e);
}
}
}
}
}
evaluate() {
this.value = this.get();
this.dirty = false;
}
depend() {
let i = this.deps.length;
while (i--) {
this.deps[i].depend();
}
}
teardown() {
if (this.active) {
// remove self from vm's watcher list
// this is a somewhat expensive operation so we skip it
// if the vm is being destroyed.
remove(this.vm && this.vm._watchers, this);
let i = this.deps.length;
while (i--) {
this.deps[i].removeSub(this);
}
this.active = false;
}
}
}
const seenObjects = new Set();
function traverse(val) {
seenObjects.clear();
_traverse(val, seenObjects);
}
function _traverse(val, seen) {
let i, keys;
const isA = _.isArray(val);
if ((!isA && !_.isObject(val))) {
return;
}
if (val.__ob__) {
const depId = val.__ob__.dep.id;
if (seen.has(depId)) {
return;
}
seen.add(depId);
}
if (isA) {
i = val.length;
while (i--) _traverse(val[i], seen);
} else {
keys = _.keys(val);
i = keys.length;
while (i--) _traverse(val[keys[i]], seen);
}
}
const arrayProto = Array.prototype;
const arrayMethods = [];
_.each([
"push",
"pop",
"shift",
"unshift",
"splice",
"sort",
"reverse"
], function (method) {
const original = arrayProto[method];
arrayMethods[method] = function mutator(...args) {
const ob = this.__ob__;
let inserted;
switch (method) {
case "push":
case "unshift":
inserted = args;
break;
case "splice":
inserted = args.slice(2);
break;
}
if (inserted) inserted = ob.observeArray(inserted);
switch (method) {
case "push":
case "unshift":
args = inserted;
break;
case "splice":
if (args.length > 2) {
args = [args[0], args[1]].concat(inserted ? inserted : []);
}
break;
}
const result = original.apply(this, args);
notify(ob.parent, ob.parentKey, ob.dep, true);
return result;
};
});
const arrayKeys = _.keys(arrayMethods);
const observerState = {
shouldConvert: true
};
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
/**
* Observer class that are attached to each observed
* object. Once attached, the observer converts target
* object's property keys into getter/setters that
* collect dependencies and dispatches updates.
*/
class Observer {
constructor(value) {
this.value = value;
this.dep = new Dep();
this.vmCount = 0;
if (_.isArray(value)) {
const augment = hasProto
? protoAugment
: copyAugment;
augment(value, arrayMethods, arrayKeys);
this.model = this.observeArray(value);
} else {
this.model = this.walk(value);
}
def(this.model, "__ob__", this);
}
walk(obj) {
return defineReactive(obj, this);
}
observeArray(items) {
for (let i = 0, l = items.length; i < l; i++) {
const ob = observe(items[i], this, i);
items[i] = ob ? ob.model : items[i];
}
return items;
}
}
function protoAugment(target, src, keys) {
Object.setPrototypeOf(target, src);
}
/* istanbul ignore next */
function copyAugment(target, src, keys) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i];
target[key] = src[key];
}
}
function observe(value, parentObserver, parentKey) {
if (!_.isObject(value)) {
return;
}
let ob;
if (value.__ob__ instanceof Observer) {
ob = value.__ob__;
} else if (
observerState.shouldConvert && isExtensible(value) &&
(_.isArray(value) || isPlainObject(value))
) {
ob = new Observer(value);
}
if (ob) {
ob.parent = parentObserver || ob.parent;
ob.parentKey = parentKey;
}
return ob;
}
function notify(observer, key, dep, refresh) {
dep.notify({ observer: observer, key: key, refresh: refresh });
if (observer) {
//触发a.*绑定的依赖
_.each(observer._deps, function (dep) {
dep.notify({ observer: observer, key: key });
});
//触发a.**绑定的依赖
let parent = observer, root = observer, route = key || "";
while (parent) {
_.each(parent._scopeDeps, function (dep) {
dep.notify({ observer: observer, key: key });
});
if (parent.parentKey != null) {
route = parent.parentKey + "." + route;
}
root = parent;
parent = parent.parent;
}
for (let _key in root._globalDeps) {
const reg = new RegExp(_key);
if (reg.test(route)) {
for (let i = 0; i < root._globalDeps[_key].length; i++) {
root._globalDeps[_key][i].notify({ observer: observer, key: _key });
}
}
}
}
}
function defineReactive(obj, observer, shallow) {
const props = {};
let model;
_.each(obj, function (val, key) {
if (key in $$skipArray) {
return;
}
let configurable = isConfigurable(obj, key);
const dep = (observer && observer["__dep" + key]) || new Dep();
observer && (observer["__dep" + key] = dep);
let childOb = configurable && !shallow && observe(val, observer, key);
props[key] = {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = childOb ? childOb.model : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (_.isArray(value)) {
dependArray(value);
}
}
}
return value;
},
set: function reactiveSetter(newVal) {
const value = childOb ? childOb.model : val;
if (newVal === value || (newVal !== newVal && value !== value)) {
return;
}
val = newVal;
childOb = configurable && !shallow && observe(newVal, observer, key);
if (childOb && value && value.__ob__) {
childOb._scopeDeps = value.__ob__._scopeDeps;
childOb._deps = value.__ob__._deps;
}
obj[key] = childOb ? childOb.model : newVal;
notify(model.__ob__, key, dep);
}
};
});
return model = createViewModel$1(obj, props);
}
function defineReactiveProperty(obj, key, val, shallow) {
const dep = new Dep();
let configurable = isConfigurable(obj, key);
if (!configurable) {
return;
}
if (arguments.length === 2) {
val = obj[key];
}
let childOb = !shallow && observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = childOb ? childOb.model : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (_.isArray(value)) {
dependArray(value);
}
}
}
return value;
},
set: function reactiveSetter(newVal) {
const value = childOb ? childOb.model : val;
if (newVal === value || (newVal !== newVal && value !== value)) {
return;
}
childOb = configurable && !shallow && observe(newVal);
val = newVal;
obj[key] = childOb ? childOb.model : newVal;
dep.notify();
}
});
}
/**
* Set a property on an object. Adds the new property and
* triggers change notification if the property doesn't
* already exist.
*/
function set(target, key, val) {
if (_.isArray(target)) {
target.length = Math.max(target.length, key);
target.splice(key, 1, val);
return val;
}
if (_.has(target, key)) {
target[key] = val;
return val;
}
const ob = (target).__ob__;
if (!ob) {
target[key] = val;
return val;
}
ob.value[key] = val;
target = defineReactive(ob.value, ob);
notify(ob, key, ob.dep);
return target;
}
function freeze() {
return Object.freeze.apply(null, arguments);
}
/**
* Delete a property and trigger change if necessary.
*/
function del(target, key) {
if (_.isArray(target)) {
target.splice(key, 1);
return;
}
const ob = (target).__ob__;
if (!_.has(target, key)) {
return;
}
if (!ob) {
delete target[key];
return target;
}
delete ob.value[key];
target = defineReactive(ob.value, ob);
notify(ob, key, ob.dep);
return target;
}
/**
* Collect dependencies on array elements when the array is touched, since
* we cannot intercept array element access like property getters.
*/
function dependArray(value) {
for (let e, i = 0, l = value.length; i < l; i++) {
e = value[i];
e && e.__ob__ && e.__ob__.dep.depend();
if (_.isArray(e)) {
dependArray(e);
}
}
}
var falsy$1;
const operators = {
"||": falsy$1,
"&&": falsy$1,
"(": falsy$1,
")": falsy$1
};
function runBinaryFunction(binarys) {
let expr = "";
for (let i = 0, len = binarys.length; i < len; i++) {
if (_.isBoolean(binarys[i]) || _.has(operators, binarys[i])) {
expr += binarys[i];
} else {
expr += "false";
}
}
return new Function("return " + expr)();
}
function routeToRegExp(route) {
route = route.replace(/\*\*/g, "[a-zA-Z0-9_]+").replace(/\*./g, "[a-zA-Z0-9_]+.");
return "^" + route + "$";
}
function watch(model, expOrFn, cb, options) {
if (isPlainObject(cb)) {
options = cb;
cb = cb.handler;
}
if (typeof cb === "string") {
cb = model[cb];
}
options = options || {};
options.user = true;
let exps;
if (_.isFunction(expOrFn) || !(exps = expOrFn.match(/[a-zA-Z0-9_.*]+|[|][|]|[&][&]|[(]|[)]/g)) || (exps.length === 1 && expOrFn.indexOf("*") < 0)) {
const watcher = new Watcher(model, expOrFn, cb, options);
if (options.immediate) {
cb(watcher.value);
}
return function unwatchFn() {
watcher.teardown();
};
}
const watchers = [];
let fns = exps.slice();
let complete = false, running = false;
const callback = function (index, newValue, oldValue, attrs) {
if (complete === true) {
return;
}
fns[index] = true;
if (runBinaryFunction(fns)) {
complete = true;
cb(newValue, oldValue, attrs);
}
if (options && options.sync) {
complete = false;
running = false;
fns = exps.slice();
} else {
if (!running) {
running = true;
nextTick(function () {
complete = false;
running = false;
fns = exps.slice();
});
}
}
};
_.each(exps, function (exp, i) {
if (_.has(operators, exp)) {
return;
}
if (exp.indexOf("*") >= 0) {
//a.**或a.*形式
if (/^[1-9a-zA-Z.]+(\*\*$|\*$)/.test(exp) || exp === "**" || exp === "*") {
const isGlobal = exp.indexOf("**") >= 0;
if (isGlobal) {
//a.**的形式
exp = exp.replace(".**", "");
} else {
//a.*的形式
exp = exp.replace(".*", "");
}
const getter = (exp === "**" || exp === "*") ? function (m) {
return m;
} : parsePath(exp);
const v = getter.call(model, model);
if (v && v.__ob__) {
const dep = new Dep();
if (isGlobal) {
(v.__ob__._scopeDeps || (v.__ob__._scopeDeps = [])).push(dep);
} else {
(v.__ob__._deps || (v.__ob__._deps = [])).push(dep);
}
const w = new Watcher(model, function () {
dep.depend();
return NaN;
}, function (newValue, oldValue, attrs) {
callback(i, newValue, oldValue, _.extend({ index: i }, attrs));
}, options);
watchers.push(function unwatchFn() {
w.teardown();
v.__ob__._scopeDeps && remove(v.__ob__._scopeDeps, dep);
v.__ob__._deps && remove(v.__ob__._deps, dep);
});
}
return;
}
// **.a.**的情况,场景:a.b.c, 如果用b.**监听, a被重新赋值b上的_scopeDes就不存在了
if (/^(\*\*\.)+[1-9a-zA-Z]+(\.\*\*$)/.test(exp)) {
//先获取到能获取到的对象
const paths = exp.split(".");
const currentModel = model[paths[1]];
if (!currentModel.__ob__) {
return;
}
exp = paths[1] + ".**";
//补全路径
let parent = currentModel.__ob__.parent, root = currentModel.__ob__;
while (parent) {
exp = "*." + exp;
root = parent;
parent = parent.parent;
}
const regStr = routeToRegExp(exp);
const dep = new Dep();
root._globalDeps || (root._globalDeps = {});
if (_.isArray(root._globalDeps[regStr])) {
root._globalDeps[regStr].push(dep);
} else {
root._globalDeps[regStr] = [dep];
}
const w = new Watcher(currentModel, function () {
dep.depend();
return NaN;
}, function (newValue, oldValue, attrs) {
callback(i, newValue, oldValue, _.extend({ index: i }, attrs));
}, options);
watchers.push(function unwatchFn() {
if (root._globalDeps) {
remove(root._globalDeps[regStr], dep);
if (root._globalDeps[regStr].length === 0) {
delete root._globalDeps[regStr];
w.teardown();
}
}
});
return;
}
// 再有结尾有*的就不支持了
if (exp[exp.length - 1] === "*") {
throw new Error("not support");
}
//其他含有*的情况,如*.a,*.*.a,a.*.a
let currentModel = model;
//先获取到能获取到的对象
const paths = exp.split(".");
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === "*") {
break;
}
currentModel = model[paths[i]];
}
exp = exp.substr(exp.indexOf("*"));
if (!currentModel.__ob__) {
return;
}
//补全路径
let parent = currentModel.__ob__.parent, root = currentModel.__ob__;
while (parent) {
exp = "*." + exp;
root = parent;
parent = parent.parent;
}
const regStr = routeToRegExp(exp);
const dep = new Dep();
root._globalDeps || (root._globalDeps = {});
if (_.isArray(root._globalDeps[regStr])) {
root._globalDeps[regStr].push(dep);
} else {
root._globalDeps[regStr] = [dep];
}
const w = new Watcher(currentModel, function () {
dep.depend();
return NaN;
}, function (newValue, oldValue, attrs) {
callback(i, newValue, oldValue, _.extend({ index: i }, attrs));
}, options);
watchers.push(function unwatchFn() {
if (root._globalDeps) {
remove(root._globalDeps[regStr], dep);
if (root._globalDeps[regStr].length === 0) {
delete root._globalDeps[regStr];
w.teardown();
}
}
});
return;
}
const watcher = new Watcher(model, exp, function (newValue, oldValue, attrs) {
callback(i, newValue, oldValue, _.extend({ index: i }, attrs));
}, options);
watchers.push(function unwatchFn() {
watcher.teardown();
});
});
return watchers;
}
const mixinInjection = {};
function getMixins(type) {
return mixinInjection[type];
}
function mixin(xtype, cls) {
mixinInjection[xtype] = _.cloneDeep(cls);
}
const computedWatcherOptions = { lazy: true };
let REACTIVE = true;
function initState(vm, state) {
if (state) {
vm.$$state = REACTIVE ? observe(state).model : state;
}
}
function initComputed(vm, computed) {
const watchers = (vm._computedWatchers = {});
defineComputed(vm, computed);
for (const key in computed) {
watchers[key] = defineComputedWatcher(vm, computed[key]);
}
}
function defineComputedWatcher(vm, userDef) {
const context = vm.$$model ? vm.model : vm;
const getter =
typeof userDef === "function"
? userDef
: userDef.get;
return new Watcher(
context,
getter || noop,
noop,
computedWatcherOptions
);
}
function defineOneComputedGetter(vm, key, userDef) {
const shouldCache = true;
const sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
};
if (typeof userDef === "function") {
sharedPropertyDefinition.get = createComputedGetter(vm, key);
sharedPropertyDefinition.set = noop;
} else {
sharedPropertyDefinition.get = userDef.get
? shouldCache && userDef.cache !== false
? createComputedGetter(vm, key)
: userDef.get
: noop;
sharedPropertyDefinition.set = userDef.set ? userDef.set : noop;
}
return sharedPropertyDefinition;
}
function defineComputed(vm, computed) {
const props = {};
for (const key in computed) {
if (!(key in vm)) {
props[key] = defineOneComputedGetter(vm, key, computed[key]);
}
}
vm.$$computed = createViewModel$1({}, props);
}
function createComputedGetter(vm, key) {
return function computedGetter() {
const watcher = vm._computedWatchers && vm._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate();
}
if (REACTIVE && Dep.target) {
watcher.depend();
}
return watcher.value;
}
};
}
function initWatch(vm, watch$$1) {
vm._watchers || (vm._watchers = []);
for (let key in watch$$1) {
const handler = watch$$1[key];
if (_.isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
vm._watchers.push(createWatcher(vm, key, handler[i]));
}
} else {
vm._watchers.push(createWatcher(vm, key, handler));
}
}
}
function createWatcher(vm, keyOrFn, cb, options) {
if (isPlainObject(cb)) {
options = cb;
cb = cb.handler;
}
if (typeof cb === "string") {
cb = vm[cb];
}
return watch(
vm.model,
keyOrFn,
_.bind(cb, vm.$$model ? vm.model : vm),
options
);
}
function initMethods(vm, methods) {
for (const key in methods) {
vm[key] =
methods[key] == null
? noop
: _.bind(methods[key], vm.$$model ? vm.model : vm);
}
}
function initMixins(vm, mixins) {
mixins = (mixins || []).slice(0);
_.each(mixins.reverse(), function (mixinType) {
const mixin$$1 = getMixins(mixinType);
for (const key in mixin$$1) {
if (typeof mixin$$1[key] !== "function") continue;
if (_.has(vm, key)) continue;
vm[key] = _.bind(mixin$$1[key], vm.$$model ? vm.model : vm);
}
});
}
function defineProps(vm, keys) {
const props = {};
// if (typeof Proxy === 'function') {
// return vm.model = new Proxy(props, {
// has: function (target, key) {
// return keys.indexOf(key) > -1;
// },
// get: function (target, key) {
// if (key in $$skipArray) {
// return props[key]
// }
// if (vm.$$computed && key in vm.$$computed) {
// return vm.$$computed[key]
// }
// if (vm.$$state && key in vm.$$state) {
// return vm.$$state[key]
// }
// return vm.$$model[key]
// },
// set: function (target, key, val) {
// if (key in $$skipArray) {
// return props[key] = val
// }
// if (vm.$$state && key in vm.$$state) {
// return vm.$$state[key] = val
// }
// if (vm.$$model && key in vm.$$model) {
// return vm.$$model[key] = val
// }
// }
// })
// }
for (let i = 0, len = keys.length; i < len; i++) {
const key = keys[i];
if (!(key in $$skipArray)) {
props[key] = {
enumerable: true,
configurable: true,
get: function () {
if (vm.$$computed && key in vm.$$computed) {
return vm.$$computed[key];
}
if (vm.$$state && key in vm.$$state) {
return vm.$$state[key];
}
if (vm.$$model && key in vm.$$model) {
return vm.$$model[key];
}
let p = vm._parent;
while (p) {
if (p.$$context && key in p.$$context) {
return p.$$context[key];
}
p = p._parent;
}
},
set: function (val) {
if (vm.$$state && key in vm.$$state) {
return (vm.$$state[key] = val);
}
if (vm.$$model && key in vm.$$model) {
return (vm.$$model[key] = val);
}
let p = vm._parent;
while (p) {
if (p.$$context && key in p.$$context) {
return (p.$$context[key] = val);
}
p = p._parent;
}
}
};
}
}
vm.model = createViewModel$1({}, props);
}
function defineContext(vm, keys) {
const props = {};
for (let i = 0, len = keys.length; i < len; i++) {
const key = keys[i];
if (!(key in $$skipArray)) {
props[key] = {
enumerable: true,
configurable: true,
get: function () {
return vm.model[key];
},
set: function (val) {
return (vm.model[key] = val);
}
};
}
}
vm.$$context = createViewModel$1({}, props);
}
function getInjectValue(vm, key) {
let p = vm._parent;
while (p) {
if (p.$$context && key in p.$$context) {
return p.$$context[key];
}
p = p._parent;
}
}
function getInjectValues(vm) {
const inject = vm.inject || [];
const result = {};
_.each(inject, function (key) {
result[key] = getInjectValue(vm, key);
});
return result;
}
class Model {
_constructor(model, destroyHandler) {
if (model instanceof Observer || model instanceof Model) {
model = model.model;
}
if (model && model.__ob__) {
this.$$model = model;
} else {
this.options = model || {};
}
this._parent = Model.target;
const state = _.isFunction(this.state) ? this.state() : this.state;
const computed = this.computed;
const context = this.context;
const inject = this.inject;
const childContext = this.childContext;
const provide = this.provide;
const watch$$1 = this.watch;
const actions = this.actions;
const keys = _.keys(this.$$model)
.concat(_.keys(state))
.concat(_.keys(computed))
.concat(inject || [])
.concat(context || []);
const mixins = this.mixins;
defineProps(this, keys);
// deprecated
childContext && defineContext(this, childContext);
provide && defineContext(this, provide);
this.$$model && (this.model.__ob__ = this.$$model.__ob__);
initMixins(this, mixins);
this.init();
initState(this, _.extend(getInjectValues(this), state));
initComputed(this, computed);
REACTIVE && initWatch(this, watch$$1);
initMethods(this, actions);
this.created && this.created();
this._destroyHandler = destroyHandler;
if (this.$$model) {
return this.model;
}
}
_init() {
}
init() {
this._init();
}
destroy() {
for (const key in this._computedWatchers) {
this._computedWatchers[key].teardown();
}
_.each(this._watchers, function (unwatches) {
unwatches = _.isArray(unwatches) ? unwatches : [unwatches];
_.each(unwatches, function (unwatch) {
unwatch();
});
});
this._watchers && (this._watchers = []);
this._computedWatchers && (this._computedWatchers = []);
this.destroyed && this.destroyed();
this.$$model = null;
this.$$computed = null;
this.$$state = null;
this.$$context = null;
this.model = {}; // 一些异步请求里访问model里的属性,这里先变成空对象,保证部分场景下不报错,其他报错会try catch
this._destroyHandler && this._destroyHandler();
}
}
function define(model) {
return REACTIVE ? new Observer(model).model : model;
}
const reactive = define;
function config(options) {
options || (options = {});
if ("reactive" in options) {
REACTIVE = options.reactive;
}
}
function toJSON(model) {
let result;
if (_.isArray(model)) {
result = [];
for (let i = 0, len = model.length; i < len; i++) {
result[i] = toJSON(model[i]);
}
} else if (model && isPlainObject(model)) {
result = {};
for (let key in model) {
if (!_.has($$skipArray, key)) {
result[key] = toJSON(model[key]);
}
}
} else {
result = model;
}
return result;
}
const version = "2.0";
export const Fix = {
version,
$$skipArray,
mixin,
Model,
define,
reactive,
config,
observerState,
Observer,
observe,
notify,
defineReactive,
defineReactiveProperty,
set,
freeze,
del,
Watcher,
cleanupDeps,
pushTarget,
popTarget,
watch,
toJSON
};