vue-data-model
v1.3.8
Published
A reactive state container system based on Vue, inspired by mobx-state-tree
Downloads
128
Maintainers
Readme
Introduction
一个类似mobx-state-tree的响应式状态容器系统(reactive state container system )。内部实现基于Vue,创建出来的对象是一个 vue 实例。这使得你在不熟悉 mobx-state-tree 的情况下,也能轻松上手,并且很容易在你现有的 vue 项目中使用。
Install
npm i vue-data-model
Example
Terminology
开始之前,让我们先统一一下术语。
type(类型)
由 types.xxx()
方法创建的对象,它具备自我描述的特性,类似于 面向对象(oop) 的 类。
state(状态)
一般通过 type(类型) 的 create()
方法创建的类型实例对象。
How to use
step 1: 使用 types.vue
定义通用类型。该方法接受 vue 组件选项(vue component options)作为唯一参数。
import { types } from 'vue-data-model';
const Todo = types.vue({
data() {
return {
name: '',
isDone: false
};
},
computed: {
length() {
return this.name.length;
}
},
methods: {
toggle() {
this.isDone = !this.isDone;
}
}
});
step 2: 通过类型的 type.create()
创建类型实例。
/* 不传参数创建 */
const defaultTodo = Todo.create();
console.log(defaultTodo.name === ''); // true
console.log(defaultTodo.isDone === false); // true
defaultTodo.toggle();
console.log(defaultTodo.isDone === true); // true
/* 传默认值来创建 */
const initialData = {name: 'todo 1'};
const todoDefaultValue = Todo.create(initialData);
console.log(todoDefaultValue.name === 'todo 1'); // true
console.log(todoDefaultValue.isDone === false); // true
/* 基于vue的响应式状态容器系统 */
console.log(Todo.create() instanceof Vue) // true
与 1.1.x 不兼容的破坏性更新:
- types.vue 在定义时,将计算一次 date()来提取子节点类型,并缓存起来。这意味着 data()将同步执行一次。 例如:
const Parent = types.vue({
data() {
return {
name: 'parent',
child: Child, // 这里访问不到Child,需要将Child的定义提升到Parent之前,或者使用types.late(() => Child)
};
},
});
const Child = types.vue({
data() {
return {
name: 'child',
};
},
});
- model 的类型节点不再支持 null/undefined 来初始化,这意味着它们是初始化的必填项。 例如:
// 接着上面的例子
Parent.create(); // will throw error
Parent.create({}); // will throw error
// correct
Parent.create({
child: {},
});
// 或者Parent的child改为types.optional(Child, () => {})或types.maybe(Child)定义
API
types
汇聚类型创建相关方法:
types.vue(vueOptions) 基于一个 vue 组件定义创建一个类型。详看:如何使用。
types.vo(typeOrLiteral, vueOptions) 基于一个 vue 组件定义创建一个类型,类似于
types.vue
,用于创建 DDD 的 Value Object。唯一区别types.vo
不需要接受 data 定义,内部将实际的值放在 value 字段下,并重载了$toValue
方法。typeOrLiteral: Value Object 的默认值或者类型。
vueOptions: vue 组件选项。
const Email = types.vo('', {
computed: {
length() {
return this.value.length;
},
isVaild() {
return /@gmail.com$/.test(this.value);
},
},
});
const VM = types.vue({
data() {
return {
email: Email,
};
},
});
const vm = VM.create({
email: '[email protected]'
});
console.log(vm.email.value); // '[email protected]'
console.log(vm.email.isVaild); // true
console.log(vm.$toValue()); // {email: '[email protected]'}
- types.literal(value)
定义一个字面量类型,与
types.union
配合时很有用。参考于mobx-state-tree
。
const L1 = types.literal(1);
console.log(L1.create(1) === 1);
console.log(L1.is(1) === true);
L1.create(); // will throw error, an equal value must be specified.
L1.create(2); // will throw error, an equal value must be specified.
- types.union(types...)
定义一个联合类型。实际开发中也许会遇到这样的情况:一个值的类型可能是类型 A,也可能是类型 B。参考于
mobx-state-tree
。
const Man = types.vue({
data() {
return {
name: '',
gender: types.literal('men'),
};
},
});
const Woman = types.vue({
data() {
return {
name: '',
gender: types.literal('women'),
};
},
});
const Humam = types.union(Man, Woman);
const humam = Humam.create({
gender: 'women',
name: 'Lucie',
});
console.log(Humam.is(humam)); // true
console.log(Woman.is(humam)); // true
console.log(Man.is(humam)); // false
console.log(Man.is(humam)); // false
- types.compose(types...)
组合多个类型成为一个新的类型。参考于
mobx-state-tree
。
const Man = types.vue({
data() {
return {
name: '',
};
},
});
const Superpower = types.vue({
data() {
return {
role: 'decent',
energyValue: 10,
};
},
computed: {
alias() {
return `A ${this.role} Hero: ${this.name}`
}
},
methods: {
lasing() {
this.energyValue = this.energyValue - 1;
// dosomething
}
}
});
const SuperMan = types.compose(Man, Superpower);
const hero = SuperMan.create({name: 'Jack'});
console.log(hero.alias); // `A decent Hero: Jack`;
console.log(SuperMan.is(hero)); // true
console.log(Man.is(hero)); // false. compose is not Class inheritance.
types.composeVo(types...) 组合多个类型成为一个新的 ValueObject 类型。跟 types.compose 的区别是,
types.compose
使用types.vue
创建新类型,而types.composeVo
使用types.vo
。types.array(type) 定义数组类型。参考于
mobx-state-tree
。
const Todo = types.vue({
data() {
return {
name: '',
}
},
methods: {
remove() {
const arr = getParent(this);
arr.splice(arr.indexOf(this), 1);
}
}
});
const TodoList = types.vue({
data() {
return {
list: types.array(Todo)
}
}
});
const todoList = TodoList.create({
list: [{name: 'get up'}]
});
console.log(todoList.$toValue());
/*
{
list: [{name: "get up"}]
}
*/
todoList.list[0].remove();
todoList.list.push({name: 'go back to sleep'})
console.log('remove' in todoList.list[0]) // true
state
- $toValue(replacer)
将 state 转成一个纯对象,只包含 data 域的内容。replacer 是
JSON.stringify(data, replacer)
的参数。
// 让我们基于 step 1 的Todo。
const todo = Todo.create({name: 'aa'});
console.log(todo.$toValue());
// {name: 'aa', isDone: false}
- $assign(data, replacer = defaultReplacer) 安全的对 state 进行赋值。
// 让我们基于 step 1 的Todo。
const todo = Todo.create({name: 'aa'});
todo.$assign({
name: 'bb',
toggle: 'foo',
boo: 'boo'
});
console.log(typeof todo.toggle === 'function'); // true
console.log('boo' in todo); // false
getParent
getParent(state, deep = 1)
获取当前state的父节点。deep表示往上查找的层级数,默认是 1。参考于 mobx-state-tree
。
// 让我们基于 types.array 的例子示范
import { types, getParent } from 'vue-data-model';
console.log(getParent(todoList.list[0], 1) === todoList.list); // true
console.log(getParent(todoList.list[0], 2) === todoList); // true