首页 > 作文

腾讯 Omi 5.0 发布 – Web 前端 MVVM 王者归来,mappingjs 强力加持

更新时间:2023-04-03 02:45:10 阅读: 评论:0

写在前面

腾讯 omi 框架正式发布 5.0,依然专注于 view,但是对 mvvm 架构更加友好的集成,彻底分离视图与业务逻辑的架构。

你可以通过 omi-cli 快速体验 mvvm:

$ npm i omi-cli -g        $ omi init-mvvm my-app    $ cd my-app         $ npm start                   $ npm run build             

npx omi-cli init-mvvm my-app 也支持(要求 npm v5.2.0+)

mvvm 演化

mvvm 其实本质是由 mvc、mvp 演化而来。

目的都是分离视图和模型,但是在 mvc 中,视图依赖模型,耦合度太高,导致视图的可移植性大大降低,在 mvp 模式中,视图不直接依赖模型,由 p(prenter)负责完成 model 和 view 的交互。mvvm 和 mvp 的模式比较接近。viewmodel 担任这 prenter 的角色,并且提供 ui 视图所需要的数据源,而不是直接让 view 使用 model 的数据源,这样大大提高了 view 和 model 的可移植性,比如同样的 model 切换使用 flash、html、wpf 渲染,比如同样 view 使用不同的 model,只要 model 和 viewmodel 映射好,view 可以改动很小甚至不用改变。

mappingjs

当然 mvvm 这里会出现一个问题, model 里的数据映射到 viewmodel 提供该视图绑定,怎么映射?手动映射?自动映射?在 asp.net mvc 中,有强大的 automapper 用来映射。针对 js 环境,我特地封装了 mappingjs 用来映射 model 到 viewmodel。

const testobj = {  same: 10,  bleh: 4,  firstname: 'dnt',  lastname: 'zhang',  a: {    c: 10  }}const vmdata = mapping({  from: testobj,  to: { aa: 1 },  rule: {    dumb: 12,    func: function () {      return 8    },    b: function () {      //可递归映射      return mapping({ from: this.a })    },    bar: function () {      return this.bleh    },    //可以重组属性    fullname: function () {      return this.firstname + this.lastname    },    //可以映射到 path    'd[2].b[0]': function () {      return this.a.c    }  }})

你可以通后 npm 安装使用:

npm i mappingjs

再举例说明:

var a = { a: 1 }va个性铃声r b = { b: 2 }asrt.deepequal(mapping({  from: a,  to: b}), { a: 1, b: 2 })

deep mapping:

qunit.test("", function (asrt) {  var a = { a: [{ name: 'abc', age: 18 }, { name: 'efg', age: 20 }], e: 'aaa' }  var b = mapping({    from: a,    to: { d: 'test' },    rule: {      a: null,      c: 13,      list: function () {        return this.a.map(function (item) {          return mapping({ from: item })        })      }    }  })  asrt.deepequal(b.a, null)  asrt.deepequal(b.list[0], a.a[0])  asrt.deepequal(b.c, 13)  asrt.deepequal(b.d, 'test')  asrt.deepequal(b.e, 'aaa')  asrt.deepequal(b.list[0] === a.a[0], fal)})

deep deep mapping:

qunit.test("", function (asrt) {  var a = { a: [{ name: 'abc', age: 18, obj: { f: 'a', l: 'b' } }, { name: 'efg', age: 20, obj: { f: 'a', l: 'b' } }], e: 'aaa' }  var b = mapping({    from: a,    rule: {      list: function () {        return this.a.map(function (item) {          return mapping({            from: item, rule: {              obj: function () {                return mapping({ from: this.obj })              }            }          })        })      }    }  })  asrt.deepequal(a.a, b.list)  asrt.deepequal(a.a[0].obj, b.list[0].obj)  asrt.deepequal(a.a[0].obj === b.list[0].obj, fal)})

omi mvvm todo 实战

定义 model:

let id = 0export default class todoitem {  constructor(text, completed) {    this.id = id++    this.text = text    this.completed = completed || fal    this.author = {      firstname: 'dnt',      lastname: 'zhang'    }  }  clone() {    return new todoitem(this.text, this.completed)  }}

todo 就省略不贴出来了,太长了,可以直接 看这里。反正统一按照面向对象程序设计进行抽象和封装。

定义 viewmodel:

import mapping from 'mappingjs'import shared from './shared'import丛林里的故事 todomodel from '../model/todo'import ovm from './other'class todoviewmodel {  constructor() {    this.data = {      items: []    }  }  update(todo) {    //这里进行映射    todo &&      todo.items.foreach((item, index) => {        this.data.items[index] = mapping({          from: item,          to: this.data.items[index],          rule: {            fullname: function() {              return this.author.firstname + this.author.lastname            }          }        })      })    this.data.projname = shared.projname  }  add(text) {    todomodel.add(text)    this.update(todomodel)    ovm.update()  }    getall() {    todomodel.getall(() => {      this.update(todomodel)      ovm.update())    })  }  changeshareddata() {    shared.projname = 'i love omi-mvvm.'    ovm.update()    this.update()  }}const vd = new todoviewmodel()export default vd
vm 只专注于 update 数据,视图会自动更新公共的数据或 vm 可通过 import 依赖

定义 view, 注意下面是继承自 modelview 而非 weelement。

import { modelview, define } from 'omi'import vm from '../view-model/todo'import './todo-list'import './other-view'define('todo-app', class extends modelview {  vm = vm  onclick = () => {    //view model 发送指令    vm.changeshareddata()  }  install() {    //view model 发送指令    vm.getall()  }  render(props, data) {    return (      <div>        <h3>todo</h3>        <todo-list items={data.items} />        <form onsubmit={this.handlesubmit}>          <input onchange={this.handlechange} value={this.text} />          <button>add #{data.items.length + 1}</button>        </form>        <div>{data.projname}</div>        <button onclick={this.onclick}>change shared data</button>        <other-view />      </div>    )  }  handlechange = e => {    this.text = e.target.value  }  handlesubmit = e => {    e.preventdefault()    if(this.text !== ''){      //view model 发送指令      vm.add(this.text)      this.text = ''    }  }})
所有数据通过 vm 注入所以指淫荡姐姐令通过 vm 发出
define('todo-list', function(props) {  return (    <ul>      {props.items.map(item => (        <li key={item.id}>          {item.text} <span>by {item.fullname}</span>        </li>      ))}    </ul>  )})

可以看到 todo-list 可以直接使用 fullname

→ 完整代码戳这里

mapping.auto

是不是感觉映射写起来略微麻烦?? 简单的还好,复杂对象嵌套很深就会很费劲。没关系 mapping.auto 拯救你!

mapping.auto(from, [to]) 其中 to 是可选参数

举个例子:

class todoitem {  constructor(text, completed) {    this.text = text    this.completed = completed || fal    this.author = {      firstname: 'dnt',      lastname: 'zhang'    }  }}const res = mapping.auto(new todoitem('task'))deepequal(res, {  author: {    firstname: "dnt",    lastname: "zhang"  },  completed: fal,  text: "task"})

你可以把任意 class 映射到简单的 json obj!那么开始改造 viewmodel:

class todoviewmodel {  constructor() {    this.data = {      items: []    }  }  update(todo) {    todo && mapping.auto(todo, this.data)    this.data.projname = shared.projname  }  ...  ...  ...

以前的一堆映射逻辑变成了一行代码: mapping.auto(todo, this.data)。当然由于没有 fullname 属性了,这里需要在视图里直接使用映射过来的 author:

define('todo-list',新年祝福语创意2021 function(props) {  return (    <ul>      {props.items.map(item => (        <li key={item.id}>          {item.text} <span>by {item.author.firstname + item.author.lastname}</span>        </li>      ))}    </ul>  )})

小结

从宏观的角度来看,omi 的 mvvm 架构也属性网状架构,网状架构目前来看有:

mobx + reacthooks + reactmvvm (omi)

大势所趋!简直是前端工程化最佳实践!也可以理解成网状结构是描述和抽象世界的最佳途径。那么网在哪?

viewmodel 与 viewmodel 之间相互依赖甚至循环依赖的网状结构viewmodel 一对一、多对一、一对多、多对多依赖 models 形成网状结构model 与 model 之间形成相互依赖甚至循环依赖的网状结构view 一对一依赖 viewmodel 形成网状结构

总结如下:

modelviewmodelviewmodel多对多多对多无关联viewmodel多对多多对多一对一view无关联一多一多对多

其余新增特性

单位 rpx 的支持

import { render, weelement, define, rpx } from 'omi'define('my-ele', class extends weelement {  css() {    return rpx(`div { font-size: 375rpx }`)  }    render() {    return (      &l李晨范冰冰分手了吗t;div>abc</div>    )  }})render(<my-ele />, 'body')

比如上面定义了半屏幕宽度的 div。

htm 支持

是谷歌工程师,preact作者最近的作品,不管它是不是未来,先支持了再说:

import { define, render, weelement } from 'omi'import 'omi-html'define('my-counter', class extends weelement {  static obrve = true  data = {    count: 1  }  sub = () => {    this.data.count--  }  add = () => {    this.data.count++  }  render() {    return html`      <div>        <button onclick=${this.sub}>-</button>        <span>${this.data.count}</span>        <button onclick=${this.add}>+</button>      </div>`  }})render(html`<my-counter />`, 'body')

你甚至可以直接使用下面代码在现代浏览器中运行,不需要任何构建工具:

hooks 类似的 api

你也可以定义成纯函数的形式:

import { define, render } from 'omi'define('my-counter', function() {  const [count, tcount] = this.u({    data: 0,    effect: function() {      document.title = `the num is ${this.data}.`    }  })  this.ucss(`button{ color: red; }`)  return (    <div>      <button onclick={() => tcount(count - 1)}>-</button>      <span>{count}</span>      <button onclick={() => tcount(count + 1)}>+</button>    </div>  )})render(<my-counter />, 'body')

如果你不需要 effect 方法, 可以直接使用 udata:

const [count, tcount] = this.udata(0)

更多的模板选择

template typecommanddescribeba templateomi init my-app基础模板typescript template(omi-cli v3.0.5+)omi init-ts my-app使用 typescript 的模板spa template(omi-cli v3.0.10+)omi init-spa my-app使用 omi-router 单页应用的模板omi-mp template(omi-cli v3.0.13+)omi init-mp my-app小程序开发 web 的模板mvvm template(omi-cli v3.0.22+)omi init-mvvm my-appmvvm 模板

star & fork

/d/file/titlepic/omi

本文发布于:2023-04-03 02:45:07,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/d841ca758d456b7535b08f79000933ef.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:腾讯 Omi 5.0 发布 – Web 前端 MVVM 王者归来,mappingjs 强力加持.doc

本文 PDF 下载地址:腾讯 Omi 5.0 发布 – Web 前端 MVVM 王者归来,mappingjs 强力加持.pdf

相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图