Skip to content

Instantly share code, notes, and snippets.

@zmmbreeze
Last active June 15, 2017 02:52
Show Gist options
  • Save zmmbreeze/8e0c97fbd99e94426e346c6fb3d79be4 to your computer and use it in GitHub Desktop.
Save zmmbreeze/8e0c97fbd99e94426e346c6fb3d79be4 to your computer and use it in GitHub Desktop.
import Vue from 'vue';
/**
* 代理字段到当前实例上
* @eg:
* const src = {name: 'b'};
* const target = {};
* proxy(['name'], target, src);
* console.log(target.name); // => b
* target.name = 'a';
* console.log(src.name); // => a
*
* @param {Object} target 代理对象
* @param {Array.<string>} keyNames 字段名数组
* @param {Object} src 被代理的目标对象
* @param {Object} options 可选配置
* @param {boolean} options.readonly 是否只读
* @param {function(string):string} options.nameTransform 字段名和被代理对象上字段名不一样,
* 可以使用此函数做转化
*/
function proxy(target, keyNames, src, options) {
const readonly = options && options.readonly;
const nameTransform = options && options.nameTransform;
keyNames.forEach((keyName) => {
const targetName = nameTransform ? nameTransform(keyName) : keyName;
const descriptor = {
enumerable: true,
writable: !readonly,
get() {
return src[targetName];
}
};
if (!readonly) {
descriptor.set = function (nextValue) {
src[targetName] = nextValue;
};
}
Object.defineProperty(target, keyName, descriptor);
});
}
/**
* 使一个类变成部分数据为Observable,利用了Vue的能力
* @param {Object} instance 类的实例
* @param {Object} options 可选配置
* @param {Object=} options.data https://vuejs.org/v2/api/#data
* @param {Object=} options.computed https://vuejs.org/v2/api/#computed
* @param {Object=} options.watch https://vuejs.org/v2/api/#watch
* @param {Array.<string>=} options.proxyNames 代理到instance上面的属性名数组
* 默认是Object.keys(options.data);
* @param {Array.<string>=} options.readonlyProxyNames 代理到instance上面的只读属性名数组
* 默认是Object.keys(options.computed);
* @param {string} vmName 默认为 _vm
*/
export default function observeData(instance, options) {
const vmName = options.vmName || '_vm';
instance[vmName] = new Vue({
data: options.data,
watch: options.watch,
computed: options.computed
});
instance.proxy = function () {
const args = Array.from(arguments);
args.unshift(this);
proxy.apply(this, args);
};
proxy(instance, options.proxyNames || Object.keys(options.data), instance[vmName]);
proxy(instance, options.readonlyProxyNames || Object.keys(options.computed), instance[vmName], {
readonly: true
});
}
/**
* 使一个类变成部分数据为Observable,利用了Vue的能力
* @param {Object} instance 类的实例
* @param {Object} options 可选配置
* @param {Object=} options.data https://vuejs.org/v2/api/#data
* @param {Object=} options.computed https://vuejs.org/v2/api/#computed
* @param {Object=} options.watch https://vuejs.org/v2/api/#watch
*/
export default function observeData(instance, options) {
Object.defineProperty(instance, '$watch', {
enumerable: true,
value: function () {
this._watchers = [];
return Vue.prototype.$watch.apply(this, arguments);
}
});
if (options.data) {
Object.keys(options.data).forEach((key) => {
const value = options.data[key];
Vue.util.defineReactive(instance, key, value);
});
}
if (options.watch) {
Object.keys(options.watch).forEach((key) => {
const value = options.watch[key];
Vue.prototype.$watch.call(instance, key, value);
});
}
if (options.computed) {
Object.keys(options.computed).forEach((key) => {
const getter = options.computed[key];
let dirty = false;
let cachedValue;
Object.defineProperty(instance, key, {
enumerable: true,
get: () => {
if (!dirty) {
return cachedValue;
}
cachedValue = getter();
return cachedValue;
}
});
instance.$watch(
function () {
cachedValue = getter.apply(this, arguments);
return cachedValue;
},
function () {
dirty = true;
}
);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment