日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

在 React 工程中利用 Mota 编写面向对象的业务模型

發(fā)布時(shí)間:2024/8/23 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在 React 工程中利用 Mota 编写面向对象的业务模型 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

摘要:?## 簡(jiǎn)述 React 是一個(gè)「視圖層」的 UI 框架,以常見(jiàn)的 MVC 來(lái)講 React 僅是 View,而我們?cè)诰帉憫?yīng)用時(shí),通常還需要關(guān)注更加重要的 model,對(duì)于 React 來(lái)講,我們常常需要一個(gè)「狀態(tài)管理」庫(kù)。然而,目前大多數(shù)針對(duì) React 的狀態(tài)管理庫(kù)都是「強(qiáng)依賴」過(guò)多的侵入本應(yīng)該獨(dú)立的業(yè)務(wù)模型中,導(dǎo)致「業(yè)務(wù)邏輯」對(duì)應(yīng)的代碼并不能輕易在其它地方重用,往往這些框架還具有「強(qiáng)排它

原文:https://zhuanlan.zhihu.com/p/33778168

簡(jiǎn)述

React 是一個(gè)「視圖層」的 UI 框架,以常見(jiàn)的 MVC 來(lái)講 React 僅是 View,而我們?cè)诰帉憫?yīng)用時(shí),通常還需要關(guān)注更加重要的 model,對(duì)于 React 來(lái)講,我們常常需要一個(gè)「狀態(tài)管理」庫(kù)。然而,目前大多數(shù)針對(duì) React 的狀態(tài)管理庫(kù)都是「強(qiáng)依賴」過(guò)多的侵入本應(yīng)該獨(dú)立的業(yè)務(wù)模型中,導(dǎo)致「業(yè)務(wù)邏輯」對(duì)應(yīng)的代碼并不能輕易在其它地方重用,往往這些框架還具有「強(qiáng)排它性」,但是「業(yè)務(wù)模型」應(yīng)該是沒(méi)有過(guò)多依賴,應(yīng)該是無(wú)關(guān)框架的,它應(yīng)該隨時(shí)可以被用在任何合適的 JavaScript 環(huán)境中,使用 mota 你可以用原生的普通的 JavaScript 代碼編寫你的「業(yè)務(wù)模型」,并讓你的「業(yè)務(wù)模型」在不同框架、不同運(yùn)行環(huán)境下重用更為容易。

mota 是一個(gè)主張「面向?qū)ο蟆沟?、支持「雙向綁定」的 React 應(yīng)用輔助庫(kù),基于 mota 你可以用純 JavaScript 為應(yīng)用編寫完全面向?qū)ο蟮摹笜I(yè)務(wù)模型」,并輕易的將「業(yè)務(wù)模型」關(guān)聯(lián)到 React 應(yīng)用中。

示例

在線 TodoList 示例
(示例源碼)

安裝

通過(guò) npm 安裝,如下

$ npm i mota --save

或通過(guò)?dawn?腳手腳加創(chuàng)建工程,如下

$ mkdir your_path $ cd your_path $ dn init -t mota $ dn dev

需要先安裝 dawn(Dawn 安裝及使用文檔)

工程結(jié)構(gòu)

一個(gè)?mota?工程的通常結(jié)構(gòu)如下

. ├── README.md ├── package.json └── src├── assets│?? ├── common.less│?? ├── favicon.ico│?? └── index.html├── components│?? ├── todoApp.js│?? └── todoItem.js├── index.js└── models├── TodoItem.js├── TodoList.js└── index.js

編寫業(yè)務(wù)模型

在 mota 中「模型」可以是由一個(gè)?class?或普通的的?Object,整個(gè)「業(yè)務(wù)模型層」會(huì)由多個(gè)?class?和多個(gè)?Object?組成,而編寫模型所需要的知識(shí)就是 JavaScript 固有的面向?qū)ο缶幊痰闹R(shí)。

如下示例通過(guò)編寫一個(gè)名為?User?的?class?創(chuàng)建了一個(gè)「用戶模型」

export default class User {firstName = 'Jack';lastName = 'Hou';get fullName(){reutrn `${this.firstName} ${this.lastName}`;} }

也可以是一個(gè)?Object,通常這個(gè)模型需要是「單例」時(shí),可采用這種方式,如下

export default {firstName: 'Jack',lastName: 'Hou',get fullName(){reutrn `${this.firstName} ${this.lastName}`;} };

在「業(yè)務(wù)模型」編寫完成后,可以通過(guò)?@model?將某個(gè)「類」或「類的實(shí)例」關(guān)聯(lián)到指定組件,關(guān)聯(lián)后便可以在組件中使用?this.model?訪問(wèn)「模型的成員變量或方法」了,mota 還會(huì)自動(dòng)「收集組件依賴」,在組件「依賴的模型數(shù)據(jù)」發(fā)生變化時(shí),自動(dòng)響應(yīng)變化并「驅(qū)動(dòng)組件重新渲染」,如下

import { model,binding } from 'mota'; import React from 'react'; import ReactDOM from 'react-dom'; import User from './models/user';@model(User) class App extends React.Component {onChange(field,event){this.model[field] = event.target.value;}render(){return <div><p>{this.model.fullName}</p><p><input onChange={this.onChange.bind(this,'firstName')}/><br/><input onChange={this.onChange.bind(this,'lastName')}/></p></div>;} }ReactDOM.render(<App/>, mountNode);

值得注意的是,在使用?@model?時(shí)如果傳入的是一個(gè)?class?最終每個(gè)組件實(shí)例都會(huì)自動(dòng)創(chuàng)建一個(gè)?獨(dú)立的實(shí)例,這樣帶來(lái)的好處是「當(dāng)一個(gè)頁(yè)面中有同一個(gè)組件的多個(gè)實(shí)例時(shí),不會(huì)相互影響」。

屬性映射

在 React 中通常會(huì)將應(yīng)用折分為多個(gè)組件重用它們,并在用時(shí)傳遞給它「屬性」,mota 提供了將「組件屬性」映射到「模型數(shù)據(jù)」的能力,基于?model?編程會(huì)讓「視圖層」更單一,專注于 UI 的呈現(xiàn),,如下

@model({ value: 'demo' }) @mapping(['value']) class Demo extends React.Component {render () {return <div>{this.model.value}</div>;} }

上邊的代碼通過(guò)?mapping?將?Demo?這個(gè)組件的?value?屬性映射到了?model.value?上,在組件的屬性?value?發(fā)生變化時(shí),會(huì)自動(dòng)同步到?model.value?中。

通過(guò)一個(gè) map 進(jìn)行映射,還可以讓「組件屬性」和「模型的成員」使用不同名稱,如下:

@model({ value: 'demo' }) @mapping({ content: 'value' }) class Demo extends React.Component {render () {return <div>{this.model.value}</div>;} }

上邊的代碼,將組件 demo 的?content?屬性映射到了?model.value?上。

自執(zhí)行函數(shù)

mota 中提供了一個(gè)?autorun?函數(shù),可用于裝飾 React 組件的成員方法,被裝飾的「成員方法」將會(huì)在組件掛載后自動(dòng)執(zhí)行一次,mota 將「收集方法中依賴的模型數(shù)據(jù)」,在依賴的模型數(shù)據(jù)發(fā)生變化時(shí)會(huì)「自動(dòng)重新執(zhí)行」對(duì)應(yīng)的組件方法。

示例

import { Component } from 'react'; import { model, autorun } from 'mota'; import DemoModel from './models/demo';@model(DemoModel) export default Demo extends Component {@autoruntest() {console.log(this.model.name);}}

上邊的示例代碼中,組件在被掛載后將會(huì)自動(dòng)執(zhí)行?test?方法,同時(shí) mota 會(huì)發(fā)現(xiàn)方法中依賴了?model.name,那么,在?model.name?發(fā)生變化時(shí),就會(huì)重新執(zhí)行?test?方法。

監(jiān)聽(tīng)模型變化

mota 中提供了一個(gè)?watch?函數(shù),可用于裝飾 React 組件的成員方法,watch?可以指定要觀察的「模型數(shù)據(jù)」,在模型數(shù)據(jù)發(fā)變化時(shí),就會(huì)自動(dòng)執(zhí)行「被裝飾的組件方法」,watch?還可以像?autorun?一樣自動(dòng)執(zhí)行一次,但它和?autorun?還是不盡相同,主要有如下區(qū)別

  • autorun?會(huì)自動(dòng)收集依賴,而?watch?不會(huì)關(guān)心組件方法中有何依賴,需要手動(dòng)指定依賴的模型數(shù)據(jù)
  • watch?默認(rèn)不會(huì)「自動(dòng)執(zhí)行」,需顯式的指定「立即執(zhí)行參數(shù)為 true」,才會(huì)自動(dòng)執(zhí)行首次。
  • autorun?依賴的是「模型數(shù)據(jù)」本身,而?watch?依賴的是「計(jì)算函數(shù)」每次的「計(jì)算結(jié)果」

示例

import { Component } from 'react'; import { model, autorun } from 'mota'; import DemoModel from './models/demo';@model(DemoModel) export default Demo extends Component {@watch(model=>model.name)test() {console.log('name 發(fā)生了變化');}}

上邊的代碼,通過(guò)?watch?裝飾了?test?方法,并指定了觀察的模型數(shù)據(jù)?model.name,那么每當(dāng)?model.name?發(fā)生變化時(shí),都會(huì)打印?name 發(fā)生了變化.

watch?是否重新執(zhí)行,取決于?watch?的作為第一個(gè)參數(shù)傳給它的「計(jì)算函數(shù)」的計(jì)算結(jié)果,每當(dāng)依賴的模型數(shù)據(jù)發(fā)生變化時(shí)?watch?都會(huì)重執(zhí)行計(jì)算函數(shù),當(dāng)計(jì)算結(jié)果有變化時(shí),才會(huì)執(zhí)行被裝飾的「組件方法」,示例

export default Demo extends Component {@watch(model=>model.name+model.age)test() {console.log('name 發(fā)生變化');}}

有時(shí),我們希望?watch?能首先自動(dòng)執(zhí)行一次,那么可通過(guò)向第二個(gè)參數(shù)傳一個(gè)?true?聲明這個(gè)?watch?要自動(dòng)執(zhí)行一次。

export default Demo extends Component {@watch(model=>model.name,true)test() {console.log('name 發(fā)生變化');}}

上邊的?test?方法,將會(huì)在「組件掛載之后自動(dòng)執(zhí)行」,之后在?model.name?發(fā)生變化時(shí)也將自動(dòng)重新執(zhí)行。

數(shù)據(jù)綁定

基本用法

不要驚詫,就是「雙向綁定」。mota?主張「面向?qū)ο蟆?#xff0c;同樣也不排斥「雙向綁定」,使用 mota 能夠?qū)崿F(xiàn)類似?ng?或?vue?的綁定效果。還是前邊小節(jié)中的模型,我們來(lái)稍微改動(dòng)一下組件的代碼

import { model,binding } from 'mota'; import React from 'react'; import ReactDOM from 'react-dom'; import User from './models/user';@model(User) @binding class App extends React.Component {render(){const { fullName, firstName, popup } = this.model;return <div><p>{fullName}</p><p><input data-bind="firstName"/><button onClick={popup}> click me </button></p></div>;} } ReactDOM.render(<App/>, mountNode);

其中的「關(guān)鍵」就是?@binding,使用?@binding?后,組件便具備了「雙向綁定」的能力,在?jsx中便可以通過(guò)名為?data-bind?的自定義?attribute?進(jìn)行綁定了,data-bind?的值是一個(gè)「綁定表達(dá)式字符串」,綁定表達(dá)式執(zhí)行的?scope?是?model?而不是?this,也就是只能與?模型的成員?進(jìn)行綁定。

會(huì)有一種情況是當(dāng)要綁定的數(shù)據(jù)是一個(gè)循環(huán)變量時(shí),「綁定表達(dá)式」寫起會(huì)較麻煩也稍顯長(zhǎng),比如

@model(userModel) @binding class App extends React.Component {render(){const { userList } = this.model;return <ul>{userList.map((user,index)=>(<li key={user.id}><input type="checkobx" data-bind={`userList[${index}].selected`}>{user.name}</li>))}</ul>;} }

因?yàn)椤附壎ū磉_(dá)式」的執(zhí)行?scope?默認(rèn)是?this.model,以及「表達(dá)式是個(gè)字符串」,看一下?userList[${index}].selected?這并不友好,為此 mota 還提供了一個(gè)名為?data-scope?的?attribute,通過(guò)它能改變要綁定的?scope,參考如下示例

@model(userModel) @binding class App extends React.Component {render(){const { userList } = this.model;return <ul>{userList.map(user=>(<li key={user.id}><input type="checkobx" data-scope={user} data-bind="selected">{user.name}</li>))}</ul>;} }

通過(guò)?data-scope?將?input?的綁定上下文對(duì)象聲明為當(dāng)前循環(huán)變量?user,這樣就可以用?data-bind?直接綁定到對(duì)應(yīng)?user?的屬性上了。

原生表單控件

所有的原生表單控件,比如「普通 input、checkbox、radio、textarea、select」都可以直接進(jìn)行綁定。其中,「普通 input 和 textrea」比較簡(jiǎn)單,將一個(gè)字符類型的模型數(shù)據(jù)與控件綁定就行了,而對(duì)于「checkbox 和 radio」 有多種不同的綁定形式。

將「checkbox 或 radio」綁定到一個(gè)?boolean?值,此時(shí)會(huì)將 checkbox 或 radio 的 checked 屬性和模型數(shù)據(jù)建立綁定,checked 反應(yīng)了?boolean?變量的值,參考如下示例

@model({ selected:false }) @binding class App extends React.Component {render(){return <div><input type="checkbox" data-bind="selected"/><input type="radio" data-bind="selected"/></div>;} }

如上示例通過(guò)?this.model.selected?就能拿到當(dāng)前 checkbox 或 radio 的選中狀態(tài)。

將 checkbox 綁定到一個(gè)「數(shù)組」,通常是多個(gè) checkbox 綁定同一個(gè)數(shù)組變量上,此時(shí)和數(shù)據(jù)建立綁定的是 checkbox 的 value,數(shù)據(jù)中會(huì)包含當(dāng)前選中的 checkbox 的 value,如下

@model({ selected:[] }) @binding class App extends React.Component {render(){return <div><input type="checkbox" data-bind="selected" value="1"/><input type="checkbox" data-bind="selected" value="2"/></div>;} }

如上示例,通過(guò)?this.selected?就能知道當(dāng)前有哪些 checkbox 被選中了,并拿到所有選中的 value

將多個(gè) radio 綁定我到一個(gè)「字符類型的變量」,此時(shí)和數(shù)據(jù)建立綁定的是 raido 的 value,因?yàn)?radio 是單選的,所以對(duì)應(yīng)的數(shù)據(jù)是當(dāng)前選中的 radio 的 value,如下

@model({ selected:'' }) @binding class App extends React.Component {render(){return <div><input type="radio" data-bind="selected" value="1"/><input type="radio" data-bind="selected" value="2"/></div>;} }

通過(guò)?this.model.selected?就能拿到當(dāng)前選中的 radio 的 value

自定義組件

但是對(duì)于一些「組件庫(kù)」中的「部分表單組件」不能直接綁定,因?yàn)?mota 并沒(méi)有什么依據(jù)可以判斷這是一個(gè)什么組件。所以 mota 提供了一個(gè)名為?bindable?的函數(shù),用將任意組件包裝成「可綁定組件」。

bindable 有兩種個(gè)參數(shù),用于分別指定「原始組件」和「包裝選項(xiàng)」

//可以這樣 const MyComponent = bindable(opts, Component); //也可這樣 const MyCompoent = bindable(Component, opts);

關(guān)建是?bindable?需要的?opts,通過(guò)?opts?我們可以造訴 mota 如何綁定這個(gè)組件,opts?中有兩個(gè)重要的成員,它的結(jié)構(gòu)如下

{value: ['value 對(duì)應(yīng)的屬性名'],event: ['value 改變的事件名'] }

所以,我們可以這樣包裝一個(gè)自定義文本輸入框

const MyInput = bindable(Input,{value: ['value'],event: ['onChange'] });

對(duì)這種「value 不需要轉(zhuǎn)換,change 能通過(guò) event 或 event.target.value 拿到值」的組件,通過(guò)如上的代碼就能完成包裝了。

對(duì)于有?onChange?和?value?的這類文本輸入組件,因?yàn)?opts 的默認(rèn)值就是

{value: ['value'],event: ['onChange'] }

所以,可以更簡(jiǎn)單,這樣就行,

const MyInput = bindable(Input);

而對(duì)于 checkbox 和 radio 來(lái)講,如上邊講到的它「根據(jù)不同的數(shù)據(jù)型有不同的綁定形式」,這就需要指定處理函數(shù)了,如下

const radioOpts = {prop: ['checked', (ctx, props) => {const mValue = ctx.getValue();if (typeof mValue == 'boolean') {return !!mValue;} else {return mValue == props.value;}}],event: ['onChange', (ctx, event) => {const { value, checked } = event.target;const mValue = ctx.getValue();if (typeof mValue == 'boolean') {ctx.setValue(checked);} else if (checked) ctx.setValue(value);}] };

通過(guò)?prop?的第二個(gè)值,能指定「屬性處理函數(shù)」,event 的第二個(gè)值能指取「事件處理函數(shù)」,處理函數(shù)的?ctx?是個(gè)特殊的對(duì)象

  • ctx.getValue?能獲取「當(dāng)前綁定的模型數(shù)據(jù)」
  • ctx.setValue?能設(shè)置「當(dāng)前綁定的模型數(shù)據(jù)」

上邊是?radio?的配置,首先,在「屬性處理函數(shù)」中通過(guò)綁定的「模型數(shù)據(jù)的類型」決定?checked最終的狀態(tài)是什么,并在函數(shù)中返回。再次,在「事件處理函數(shù)」中通過(guò)綁定的「模型數(shù)據(jù)的類型」決定將什么值回寫到模型中。

通過(guò)「屬性處理函數(shù)」和「事件處理函數(shù)」幾乎就能將任意的自定義組件轉(zhuǎn)換為「可綁定組件」了。

另外,對(duì)于常見(jiàn)的?CheckBox?和?Radio?類型的組件 mota 也提供了內(nèi)建的?opts?配置支持,如果一個(gè)自定義組件擁有和「原生 checkbox 一致的屬性和事件模型」,那邊可以直接用簡(jiǎn)單的方式去包裝,如下

const MyCheckBox = bindable('checkbox',CheckBox); const MyRadio = bindable('radio',Radio);

好了,關(guān)于綁定就這些了。

文檔

  • 快速開(kāi)始
  • 編寫業(yè)務(wù)模型
  • 將組件屬性映射到模型
  • 自執(zhí)行函數(shù)
  • 監(jiān)聽(tīng)模型變化
  • 將模型數(shù)據(jù)與表單綁定

鏈接

  • 開(kāi)源地址
  • 版本發(fā)布日志
  • MIT 開(kāi)源協(xié)議


識(shí)別以下二維碼,干貨


總結(jié)

以上是生活随笔為你收集整理的在 React 工程中利用 Mota 编写面向对象的业务模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。