Кратко
React — это структура пользовательского интерфейса «уровня просмотра». В обычном MVC React — это просто представление. Когда мы пишем приложения, нам обычно нужно обращать внимание на более важные модели. Для React нам часто нужна «библиотека управления состоянием». Однако в настоящее время большинство библиотек управления состоянием для React являются «сильными зависимостями», которые вторгаются в бизнес-модель, которая должна быть независимой, поэтому код, соответствующий «бизнес-логике», нельзя легко повторно использовать в другом месте. ", но "бизнес-модель" не должна иметь слишком много зависимостей, она не должна зависеть от фреймворка и должна быть готова к использованию в любой подходящей среде JavaScript. Используя mota, вы можете использовать нативный обычный код JavaScript Напишите свой "бизнес модель» и упростить повторное использование вашей «бизнес-модели» в разных средах и средах выполнения.
mota — это «объектно-ориентированная» вспомогательная библиотека приложения React, которая поддерживает «двустороннюю привязку». На основе mota вы можете написать полностью объектно-ориентированную «бизнес-модель» для приложения на чистом JavaScript и легко связать «бизнес-модель». модель" в приложение React.
Связь
- Git Repo: https://github.com/Houfeng/mota, добро пожаловать Звезда
- Документация: http://houfeng.net/mota
Пример
Пример онлайн-списка задач (Пример исходного кода)
Установить
Установить через npm следующим образом
$ npm i mota --save
или поdawn
Добавьте шаги, чтобы создать проект, как показано ниже.
$ mkdir your_path
$ cd your_path
$ dn init -t mota
$ dn dev
Вам нужно сначала установить рассвет (Документация по установке и использованию Dawn)
Инженерное сооружение
Одинmota
Обычная структура проекта выглядит следующим образом.
.
├── 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
Напишите бизнес-модель
В мота "модель" может быть определенаclass
или обычныйObject
, весь «уровень бизнес-модели» будет состоять из несколькихclass
и несколькоObject
композиции, а знание, необходимое для написания модели, — это знание объектно-ориентированного программирования, присущее JavaScript.
Следующий пример работает, записывая файл с именемUser
изclass
Создал «Модель пользователя»
export default class User {
firstName = 'Jack';
lastName = 'Hou';
get fullName(){
reutrn `${this.firstName} ${this.lastName}`;
}
}
также может бытьObject
, обычно, когда эта модель должна быть «одноэлементной», этот метод можно использовать следующим образом.
export default {
firstName: 'Jack',
lastName: 'Hou',
get fullName(){
reutrn `${this.firstName} ${this.lastName}`;
}
};
После того, как "бизнес-модель" написана, можно переходить@model
Свяжите «класс» или «экземпляр класса» с указанным компонентом, а затем его можно будет использовать в компоненте после ассоциации.this.model
После доступа к «переменным-членам или методам модели» mota также автоматически «собирает зависимости компонентов». Когда компонент «зависимые данные модели» изменяется, он автоматически реагирует на изменения и «управляет повторным рендерингом компонента», как следует
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
Если входящий являетсяclass
В конечном итоге каждый экземпляр компонента будет автоматически создавать один独立的实例
, преимущество этого заключается в том, что «когда на странице есть несколько экземпляров одного и того же компонента, они не будут влиять друг на друга».
сопоставление атрибутов
В React приложение обычно делится на несколько компонентов для их повторного использования и передачи ему «свойств» при их использовании Mota предоставляет возможность сопоставлять «свойства компонента» с «данными модели» на основеmodel
Программирование сделает «уровень просмотра» более единым, сосредоточив внимание на представлении пользовательского интерфейса следующим образом.
@model({ value: 'demo' })
@mapping(['value'])
class Demo extends React.Component {
render () {
return <div>{this.model.value}</div>;
}
}
Код выше проходитmapping
БудуDemo
этого компонентаvalue
атрибут сопоставляется сmodel.value
выше, в свойствах компонентаvalue
Когда происходит изменение, оно автоматически синхронизируется сmodel.value
середина.
Сопоставление через карту также может позволить «свойствам компонентов» и «членам модели» использовать разные имена, как показано ниже:
@model({ value: 'demo' })
@mapping({ content: 'value' })
class Demo extends React.Component {
render () {
return <div>{this.model.value}</div>;
}
}
Приведенный выше код, демонстрация компонентаcontent
атрибут сопоставляется сmodel.value
начальство.
самовыполняющаяся функция
мота обеспечиваетautorun
Функция, которую можно использовать для декорирования методов-членов компонентов React.Декорированный «метод-член» будет автоматически выполняться один раз после монтирования компонента, и mota «соберет данные модели, от которых зависит метод», которые будут использоваться при изменении данных зависимой модели "Автоматически повторно выполнять" соответствующий метод компонента.
Пример
import { Component } from 'react';
import { model, autorun } from 'mota';
import DemoModel from './models/demo';
@model(DemoModel)
export default Demo extends Component {
@autorun
test() {
console.log(this.model.name);
}
}
В приведенном выше примере кода компонент будет автоматически выполнен после его монтирования.test
метод, и mota обнаружит, что метод зависит отmodel.name
, затем вmodel.name
Когда происходит изменение, оно будет выполнено повторноtest
метод.
Слушайте изменения модели
мота обеспечиваетwatch
функции, которые можно использовать для украшения методов-членов компонентов React,watch
Вы можете указать "данные модели" для наблюдения. Когда данные модели изменяются, "метод декорированного компонента" будет выполняться автоматически.watch
Так же какautorun
то же самое, что автоматически один раз, но это то же самое, что иautorun
Все же не то же самое, основные отличия заключаются в следующем
-
autorun
будет автоматически собирать зависимости, иwatch
Не заботится о каких-либо зависимостях в методе компонента, вам нужно вручную указать зависимые данные модели -
watch
По умолчанию «автоматическое выполнение» не выполняется, и для автоматического выполнения в первый раз необходимо явно указать «параметр немедленного выполнения — true». -
autorun
Зависит от самих «данных модели», иwatch
Каждый раз зависит от «результата расчета» «функции расчета»
Пример
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 发生了变化');
}
}
Код выше, черезwatch
украшенtest
метод и задает наблюдаемые данные моделиmodel.name
, то всякий разmodel.name
Когда есть изменение, он будет печататьname 发生了变化
.
watch
Выполнять ли повторно, зависит отwatch
Результат вычисления «расчетной функции», передаваемой ей в качестве первого параметра, при каждом изменении данных зависимой модели.watch
Функция расчета будет выполнена повторно, при изменении результата расчета будет выполнен декорированный «метод компонента».
export default Demo extends Component {
@watch(model=>model.name+model.age)
test() {
console.log('name 发生变化');
}
}
Иногда мы желаемwatch
может выполняться автоматически один раз, затем вы можете передатьtrue
заявить об этомwatch
Выполняется автоматически один раз.
export default Demo extends Component {
@watch(model=>model.name,true)
test() {
console.log('name 发生变化');
}
}
вершинаtest
метод, будет выполняться автоматически после монтирования компонента, а затем вmodel.name
Он также будет автоматически выполняться повторно, когда происходит изменение.
привязка данных
Основное использование
Не удивляйтесь, это «двусторонняя привязка».mota
Оправеющиеся «объектно-ориентированные», которые не исключают «двусторонние привязки» и используют MOTA для реализации подобныхng
илиvue
связывающий эффект. Все та же модель в предыдущем разделе, немного изменим код компонента
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);
"Ключ" это@binding
,использовать@binding
После этого компонент имеет возможность «двухсторонней привязки».jsx
можно назвать поdata-bind
обычайattribute
граница,data-bind
Значение представляет собой «строку выражения привязки», которую выполняет выражение привязки.scope
даmodel
вместоthis
, то есть только с模型的成员
связывать.
В одном случае, когда данные для привязки являются переменной цикла, «выражение привязки» будет более проблематичным и немного более длинным для записи, например
@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>;
}
}
Из-за выполнения «выражения привязки»scope
По умолчаниюthis.model
, а «выражение — это строка», см.userList[${index}].selected
Это не по-дружески, потому что эта мота также обеспечиваетdata-scope
изattribute
, с помощью которого он может изменить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>;
}
}
пройти черезdata-scope
Будуinput
Объект контекста привязки, объявленный как текущая переменная циклаuser
, так что вы можете использоватьdata-bind
связываться непосредственно с соответствующимuser
свойства включены.
Собственные элементы управления формой
Все собственные элементы управления формы, такие как «обычный ввод, флажок, радио, текстовое поле, выбор», могут быть напрямую привязаны. Среди них «обычный ввод и текстовое поле» относительно просты, просто привяжите данные модели символьного типа к элементу управления, и существует множество различных форм привязки для «флажка и радио».
Привяжите «флажок или радио» кboolean
значение, в это время проверенный атрибут флажка или радио будет привязан к данным модели, и проверенный ответит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>;
}
}
Передайте пример вышеthis.model.selected
Вы можете получить выбранное состояние текущего флажка или радио.
Привяжите флажок к "массиву", обычно несколько флажков привязаны к одной и той же переменной массива. В это время значение флажка привязано к данным, и данные будут содержать значение выбранного в данный момент флажка, как показано ниже.
@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>;
}
}
Как в примере выше, поthis.selected
Вы можете узнать, какие флажки в данный момент выбраны, и получить все выбранные значения.
Я привязываю несколько радиостанций к «переменной типа символа». В это время значение рейдо привязано к данным. Поскольку радио выбрано одиночно, соответствующие данные являются значением текущего выбранного радио, как показано ниже.
@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>;
}
}
пройти черезthis.model.selected
Вы можете получить значение текущего выбранного радио
пользовательский компонент
Но для некоторых "компонентов неполной формы" в "библиотеке компонентов" он не может быть напрямую привязан, потому что у mota нет оснований судить о том, что это за компонент. Таким образом, Mota обеспечиваетbindable
Функция, которая превращает любой компонент в «привязываемый компонент».
bindable имеет два параметра, используемых для указания «исходных компонентов» и «параметров пакета» соответственно.
//可以这样
const MyComponent = bindable(opts, Component);
//也可这样
const MyCompoent = bindable(Component, opts);
Гуань Цзяньbindable
потребностиopts
,пройти черезopts
Мы можем сказать mota, как связать этот компонент,opts
Есть два важных члена, его структура выглядит следующим образом
{
value: ['value 对应的属性名'],
event: ['value 改变的事件名']
}
Итак, мы можем обернуть пользовательское поле ввода текста, как это
const MyInput = bindable(Input,{
value: ['value'],
event: ['onChange']
});
Для этого типа «значение не нужно преобразовывать, изменение может получить значение через событие или event.target.value», упаковка может быть завершена с помощью приведенного выше кода.
за тоonChange
а такжеvalue
, потому что значение opts по умолчанию равно
{
value: ['value'],
event: ['onChange']
}
Так можно и проще, вот так,
const MyInput = bindable(Input);
Для флажка и радио, как упоминалось выше, он «имеет разные формы привязки в соответствии с разными типами данных», что требует указания функции обработки следующим образом.
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);
}]
};
пройти черезprop
Второе значение может указывать «обработчик атрибутов», второе значение относится к событию, которое может принимать обработчик «обработчик событий».ctx
это специальный объект
-
ctx.getValue
Может получить «текущие данные привязанной модели» -
ctx.setValue
Можно установить «текущие связанные данные модели»
вершинаradio
Конфигурация, в первую очередь, определяется привязанным «типом данных модели» в «обработчике свойства»checked
Что является конечным состоянием и возвращается в функции. Опять же, в «обработчике событий» то, какое значение записывается обратно в модель, определяется связанным «типом данных модели».
Почти по «функции обработки свойств» и «Функции обработки событий» могут быть преобразованы в «Привязывание компонентов».
Кроме того, для общегоCheckBox
а такжеRadio
Компоненты типа mota также обеспечивают встроеннуюopts
Поддержка конфигурации, если пользовательский компонент имеет тот же атрибут и модель событий, что и «собственный флажок», его можно просто упаковать следующим образом.
const MyCheckBox = bindable('checkbox',CheckBox);
const MyRadio = bindable('radio',Radio);
Ну вот и все для привязки.