vuex-orm简介

前情提要

前端开发中会难免会遇到复杂表单提交的情况,我自己也实现过一个非常非常巨大的表单,是关于个人信息录入的。数据结构大体如下;

{
    basic: {
      name: { familyName, givenName},
      birthday: new Date(),
      sex: '', //28 different types
      phone: [],
      address: [/*{nation, zip, prefecture, line1, line2,... }*/ ],
      additionItems: [],
    },
    education: [/*{category, school, degree, department, major ...} */],
    ...
}

我当时的实现是把各级表单项动态存入vuex里,点击提交后一并发给后端。但这里的问题是,我需要写很多很多的action和mutation方法;如果是education这样的数组结构的话,还需要动态支持增删改操作;数据结构的维护变得及其麻烦,此外还得注意类型检查。头痛一番后,业务是跑起来了,但是代码一直很脆,bug不断。这时候就特别怀念数据库了,假如能有表单结构来管理这类数据就好了。

vuex-orm

最近我在github上看到了一个叫vuex-orm的项目,star超过700,顿生敬意。它是vuex的一款插件,顾名思义,实现了Vuex Store的对象关系映射。我这里就稍事介绍一下用法:

创建Model

ORM需要先定义对象的数据结构(schema),vuex-orm的实现方式是继承它的Model类:

// @/model/User.js
import { Model } from '@vuex-orm/core'

export default class User extends Model {
  // This is the name used as module name of the Vuex Store.
  static entity = 'users'

  // list all the fields (schema)
  static fields () {
    return {
      id: this.increment(), //  id increases automatically
      name: this.string(''),  // define as a string and the defualt value is ''
    }
  }
}

插件安装

接着是给vuex安装插件。如下所示,我们先在vuex-orm的database里注册自定义的model,然后把它安装到Vuex store里。

// store.js
import Vue from 'vue'
import Vuex from 'vuex'
import VuexORM from '@vuex-orm/core'
import User from '@/model/User'

Vue.use(Vuex)

// Create a new database instance.
const database = new VuexORM.Database()

// Register Models to the database.
database.register(User)

// Create Vuex Store and register database through Vuex ORM.
const store = new Vuex.Store({
  plugins: [VuexORM.install(database)]
})

export default store

Model in VUE

这时候就可以在vue里自在地使用model了,

// user.vue
<script>
import UserModel from '@/model/User'

export default {
  ...
  created () {
    const data = [{name: 'Onion'}, {name: 'Garlic'}]
    UserModel.create({data})
    // this.$store.dispatch('entities/users/create', {data} )
  },
}
</script>

用vue devtool查看一下state,结构如下:

{
    entities: { 
        $name: 'entities',
        users: { 
            $connection: 'entities',
            $name: 'users',
            data: { 
                1: { 
                    $id: 1,
                    id: 1,
                    name: 'Onion'
                },
                2: { 
                    $id: 2,
                    id: 2,
                    name: 'Garlic'
                }
            }
        }
    }
}

嗯,数据成功写入,user的id自增从1开始。事实上UserModel.create({data})只是封装了this.$store.dispatch('entities/users/create', {data} )方法。Vuex-orm加载后会帮你创建一系列的gettersmutations方法,它们分别映射了Model的增删改查。如果不想import UserModel,你也可以直接使用相应的this.$store.dispatch实现数据读写。

CRUD

再列几个读写方法

  • create

    UserModel.insert({data: {name: 'Ginger'} })
    
  • update

    UserModel.update({
        where: 2,
        name: 'Ginger',
    })
    
  • delete

    delete可以直接删除id指向的对象,也可以使用where语句。

    UserModel.delete(1)
    
    UserModel.delete({
        where: (obj) => obj.id === 1 
    })
    
  • retrive data

    读取数据可以用allfindquery等方法,query甚至可以添加whereorderBylimit等语句。

    const user = UserModel.query().where('name', 'Onion').get()
    

关系映射

vuex-orm还实现了一套主外键的关系映射,有One To OneOne to ManyMany to Many等八九种关联。写一个简单的例子:

class Todo extends Model {
  static entity = 'todos'

  static fields () {
    return {
      id: this.increment(),
      user_id: this.number(0),
      title: this.string(''),
      done: this.boolean(false),
    }
  }
}

class User extends Model {
  static entity = 'users'

  static fields () {
    return {
      id: this.increment(),
      name: this.string(''),
      todos: this.hasMany(Todo, 'user_id')
    }
  }
}

如上所示,我们将User与Todo一起关联,hasMany表示一对多的关系,user_id为外键。创建一个todo如下,user_id是1,就是Onion这个人。

TodoModel.insert({
    data: {
      title: 'Hello',
      user_id: 1,
    }})

再看一下state

users: { 
    $connection: 'entities',
    $name: 'users',
    data: { 
        1: { 
            $id: 1,
            id: 1,
            name: 'Onion',
            todos: [
                1: {
                    $id: 1,
                    id: 1,
                    title: 'Hello',
                    user_id: 1,
                    done: false,
                }
            ]
        },
        ...
    }
}

嗯,成功加到user的todos数组里了。

小结

除了上面一些基本功能外,vuex-orm还有其他一些高级用法,这里就不一一介绍了,大家有兴趣的话可以去官方wiki查看。

自从前端渲染框架和flux设计模式流行后,现代web开发把主要的业务实现放在了前端。后端愈发轻领域设计,更像是一个单纯的数据读写接口;rest设计也变得大颗粒化。新工具的不断跟进在这里起到了关键性的作用。

Vuex-orm也来自于Redux相关插件的设计理念。以前我还断言Graphql出现后Redux之类的state管理工具会开始式微,现在想想还是自己太狭隘了。无知与狭隘共生。

学无止境,互勉。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容