- Notifications
You must be signed in to change notification settings - Fork2
📝Webpack loader for Omi.js React.js and Rax.js components 基于 Omi.js,React.js 和 Rax.js 单文件组件的 Webpack 模块加载器
Wscats/omil
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
English | 简体中文
omil
是一个 webpack 的 loader,它允许你以一种名为单文件组件(SFCs)
的格式撰写 Omi 组件:
<templatelang="html"name="component-name"><headeronClick="${this.test}">${this.data.title}</header></template><script>exportdefaultclass{test(){console.log('Hello Eno!')}install(){this.data={title:'Omi'}}}</script><style>header {color:#58bc58; }</style>
Omil 还提供了很多酷炫的特性:
- 允许为 Omi 组件的每个部分使用其它的 webpack loader,例如在
<style>
的部分使用 Sass 和在<template>
的部分使用 jsx; - 允许在一个 .omi 文件中使用自定义块,并对其运用自定义的 loader 链;
- 使用 webpack loader 将
<style>
和<template>
中引用的资源当作模块依赖来处理; - 在开发过程中使用热重载来保持状态。
简而言之,webpack 和 Omi Loader 的结合为你提供了一个现代、灵活且极其强大的前端工作流,来帮助撰写 Omi.js 应用。
如果你不想手动设置 webpack,我们推荐使用Omi CLI 直接创建一个项目的脚手架。通过 Omi CLI 创建的项目会针对多数常见的开发需求进行预先配置,做到开箱即用。
如果Omi CLI
提供的内建没有满足你的需求,或者你乐于从零开始创建你自己的 webpack 配置,那么请继续阅读这篇指南。
首先先安装好Omil
npm install -D omil
如果你使用的是Visual Studio Code 进行开发,强烈建议下载Omi Snippets 扩展,它会提供给你语法高亮,局部编译等功能。您可以在 VSC 扩展界面里面搜索 omi 这个关键词出现Omi Snippets
点击安装即可,稍等片刻,当它安装成功后会提醒你需要重新加载编辑工具,点击重新加载即可使用。
每个Omil
包的新版本发布时,一个相应版本的Omi Snippets
也会随之发布。
Omi Loader 的配置和其它的 loader 基本一样。
// webpack.config.jsmodule.exports={module:{rules:[// ... 其它规则{test:/\.omi|eno$/,loader:'omil'}]}}
一个更完整的 webpack 配置示例看起来像这样:
module.exports={mode:'development',module:{rules:[{test:/\.omi|eno$/,use:[{loader:require.resolve('omil'),options:{// Use in development, You should remove in productionsourceMaps:'both',// Config babel plugins for async, await and other many featuresplugins:[["@babel/plugin-transform-runtime",{"absoluteRuntime":false,"corejs":false,"helpers":true,"regenerator":true,"useESModules":false}]]}}],// Or you can use eno-loader or omil directly// use: ['eno-loader']// use: ['omil']}]}}
在配置完 Omil 之后,我们可以在 VS Code 上同时安装好Omi Snippets 扩展,这个插件可以方便的让你把 .omi 和 .eno 后缀文件在未经过 webpack 处理前转化为 .js 文件,让你可以直观了解到单文件组件经过 omil 转化后的 JS 文件内容,这相当于局部编译减轻 webpack 处理单文件时候的不必要消耗。
例如你在 webpack 的入口文件夹中有一个 .omi 的后缀文件,当你新建并经过编辑保存之后,Omi Snippets扩展会在同级目录下新建一份同名但不同后缀的 .js 文件
- src
- Hello.omi
- Hello.js
Hello.omi | 开发中你需要编写的单文件组件 |
---|---|
Hello.js | 修改或者保存文件Hello.omi 后经过插件转化的js文件 |
如下图,左边的代码是我们编写的 .omi 后缀的单文件组件,右边是经过 Omi Snippets 生成的 .js 后缀文件。
上图的示例代码如下
<template>
标签负责放 JSX 的内容,属性name="my-test"
为该组件的名字,后面可以在 JSX 中用<my-text>
使用该组件;<script>
标签负责放入组件的逻辑文件,固定的结构为export default class { // 你的代码 }
或者为export default HOC(class { // 你的代码 })
两种形式,第一种是定义类组件,第二种用来定义高阶组件,你的代码部分可以放入生命周期,函数等;<style>
标签负责定义该组件的局部样式
<templatename="my-test"><divclass="example"> { this.data.msg }</div></template><script>exportdefaultclass{install(){this.data={msg:'Hello world!'}}}</script><style>.example {color: red;}</style>
以下代码就是经过 Omi Snippets 生成的 .js 后缀文件,可以用于在你没有 omil 模块下,主逻辑文件或者其他组件引入调用。
import{WeElement,define,h}from"omi";classMyTestextendsWeElement{render(){returnh("div",{class:"example"},this.data.msg);}install(){this.data={msg:"Hello world!"};}}MyTest.css=`.example { color: red;}`;define("my-test",MyTest);
安装 React 脚手架和一些必要模块。
npm install create-react-app# 初始化项目create-react-app my-project# 进入项目文件夹目录cd my-project# 安装项目依赖npm install# 安装 styled-components 这个务必得安装 用于处理 React 单文件组件局部样式npm install styled-components --save# 安装 omil 处理React单文件组件,把 .omi 或者 .eno 后缀文件处理为 JSnpm install omil --save-dev
在配置完 Omil 之后,我们可以在 VS Code 上同时安装好Omi Snippets 扩展,这个插件可以方便的让你把 .omi 和 .eno 后缀文件在未经过 webpack 处理前转化为 .js 文件,让你可以直观了解到单文件组件经过 omil 转化后的 JS 文件内容,这相当于局部编译减轻 webpack 处理单文件时候的不必要消耗。
现在你可以使用单文件组件来编写 React 组件,默认生成类组件。
- name属性值是组件名要满足 React 框架的组件名字定义规范,首字母必须大写字母;
<template>
模板中不能有<script>
和<style>
代码片段。
<templatename="Component-name"><div><p>{this.state.title}</p></div></template><script>exportdefaultclass{constructor(props){super(props)this.state={title:"react"}}componentDidMount(){console.log('生命周期')}}</script><style>p {color:#58bc58};</style>
以上文件经过 Omil 处理后将会转化为以下代码:
import{ComponentasWeElement,createElementash}from"react";importstyledfrom"styled-components";constStyledComponents=styled.div` /* CSS */ p { color: #58bc58; }`;classComponentNameextendsWeElement{render(){returnh(StyledComponents,null,h("div",null,h("p",null,this.state.title)));}constructor(props){super(props);this.state={title:"react"};}componentDidMount(){console.log("生命周期");}}ComponentName.css=`/* CSS */p {color: #58bc58};`;exportdefaultComponentName;
.omi 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Omi 组件。每个 .omi 文件包含三种类型的顶级语言块<template>
、<script>
和<style>
:
<templatename="my-test"><divclass="example"> { this.data.msg }</div></template><script>exportdefaultclass{install(){this.data={msg:'Hello world!'}}}</script><style>.example {color: red;}</style>
Omil 会解析文件,提取每个语言块,如有必要会通过其它 loader 处理,最后将他们组装成一个 ES Module,它的默认导出是一个 Omi.js 组件定义好的自定义标签对象。
Omil 支持使用非默认语言,比如 CSS 预处理器,预编译的 HTML 模版语言,通过设置语言块的 lang 属性。例如,你可以像下面这样使用 Sass 语法编写样式:
<stylelang="sass">/* write Sass! */</style>
每个 .omi 文件最多包含一个<template>
块。
内容将被提取,如果是 JSX 会编译为函数片段,如果为 html 会编译为字符串,并最终注入到从<script>
导出的组件 render 函数中。
定义name="xxx-xxx"
可以给组件定义一个名字,这个名字会自动调用 omi 框架的define('xxx-xxx', xxxXxx)
方法来注册组件,你就可以在页面中用这个属性名<xxx-xxx></xxx-xxx>
来使用该组件
注意:
- name属性值是组件名要满足 omi 框架的组件名字定义规范,首字母不能用大写字母,并且中间必须有
-
字符; <template>
模板中不能有<script>
和<style>
代码片段。
<templatename="my-test"><divclass="example"> { this.data.msg }</div></template>
在页面容器中如此使用
<my-test/><my-test></my-test>
定义name="XxxXxx"
可以给组件定义一个名字,这个名字会自动调用 React 框架的React.Component
方法来定义类组件,你就可以在页面中用这个属性名<XxxXxx></XxxXxx>
来使用该组件
注意:
- name属性值是组件名要满足 React 框架的组件名字定义规范,首字母必须大写字母;
<template>
模板中不能有<script>
和<style>
代码片段。
<templatename="MyTest"><divclass="example"> { this.data.msg }</div></template>
在页面容器中如此使用
<MyTest/><MyTest></MyTest>
默认情况下,我们的<template>
模板是使用 JSX 语法,如果我们增加属性lang = "html"
,就可以支持编写html格式的字符串模板,你可以使用 ES6 的语法来编写 html 模板<div>${ this.data.msg }<div>
,Omil 和 Omi-Snippets 会自动帮你引入Omi.html()
方法帮你在客户端进行处理,会有一定的性能损耗,一般情况下不建议使用。
<templatename="my-test"lang="html"><divclass="example"> ${ this.data.msg }</div></template>
每个 .omi 文件最多包含一个<script>
块。
如果我们使用过 react 我们会了解到组件通常有两种定义方式,一种是函数组件,一种是类组件,Omil 默认是帮你创建类组件,我们在export default class { // 你的代码 }
或者module.exports = class { // 你的代码 }
片段中写入你的组件逻辑代码,
注意:
- 定义类组件必须是
export default class { // 你的代码 }
这种写法,class MyText {} ; export default MyText
这种写法不可以,因为 Omil 和 Omil Snippets 只识别连续的export default class
这段字符串
export default class { // 你的代码 } | 可以 | 建议使用 |
---|---|---|
module.exports = class { // 你的代码 } | 可以 | 支持 |
class MyText { // 你的代码 } export default MyText | 不可以 | 不支持 |
class MyText { // 你的代码 } module.export = MyText | 不可以 | 不支持 |
<script>exportdefaultclass{install(){this.data={msg:'Hello world!'}}}</script>
有时候我们可以使用高阶组件拓展组件本身的一些功能,高阶组件跟类组件一样,只支持下面规定的写法。
export default HOC(class { // 你的代码 }) | 可以 | 建议使用 |
---|---|---|
module.exports = HOC(class { // 你的代码 }) | 可以 | 支持 |
class MyText { // 你的代码 } export default HOC(MyText) | 不可以 | 不支持 |
class MyText { // 你的代码 } module.export = HOC(MyText) | 不可以 | 不支持 |
<script>exportdefaultHOC(class{install(){this.data={msg:'Hello world!'}}})</script>
下面是一个高阶组件的详细参考例子
<templatename="MyTest"><div><p>{this.state.title}</p></div></template><script>// 高阶函数constHOC=(props)=>{return(WraooedComponent)=>{returnclassHOCextendsWeElement{render(){return(<div><WraooedComponentname={{ ...this.props}}/></div>)}}}}exportdefaultHOC({age:18})(class{install(){this.data={msg:'Hello world!'}}})</script><stylelang="scss">p {color:#58bc58; }</style>
或者你可以这样写
<templatename="MyTest"> {HOC(<div><p>{this.state.title}</p></div>)}</template><script>// 高阶函数constHOC=(props)=>{return(WraooedComponent)=>{returnclassHOCextendsWeElement{render(){return(<div><WraooedComponentname={{ ...this.props}}/></div>)}}}}exportdefaultclass{install(){this.data={msg:'Hello world!'}}}</script><stylelang="scss">p {color:#58bc58; }</style>
通常情况下,你可以在代码中使用ES6的语法,甚至一些新特性,例如:static
,某些情况下我们需要转化为ES5做兼容,我们可以添加属性type="text/babel"
<script>exportdefaultclass{staticname='Eno Yao'install(){this.data={msg:'Hello world!'}}}</script>
一个 .omi 文件可以包含一个<style>
标签。
<style>
标签的样式本身具有局部样式的特性,这取决于 Omi 的设计是 Web Components,这有点类似于 Vue 的 scoped 属性。
<style>.example {color: red;}</style>
我们还可以使用lang = "scss"
来书写 scss 样式,它会自动帮我们编译为 css 格式内容
<stylelang = "scss">$color: red;.example { color: $color;}</style>
建议使用 VS Code 配合 Omi Snippets (该扩展支持语法高亮)扩展开发 Omi 项目,当然你可以把 .omi 文件当作 HTML 对待。
在语言块中使用该语言块对应的注释语法 (HTML、CSS、JavaScript 等)。
JSX 注释语法 | {/* comment contents here */} |
---|---|
HTML 注释语法 | <!-- comment contents here --> |
观察下面这段代码模板:
<templatename="component-name"><headeronClick={this.test}>{this.data.title}</header></template>
这个有趣的标签语法既不是字符串也不是 HTML。
它被称为 JSX,是一个 JavaScript 的语法扩展。我们建议在 Omi 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。
上面的代码事实上会自动编译为下面这份 js 代码
import{WeElement,define,h}from"omi";classComponentNameextendsWeElement{render(){returnh("div",{onClick:this.testClick},this.data.title);}}define("component-name",ComponentName);
Omi 和 React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。
Omil和Omi Snippets都支持编译Omi和React,编译的区别取决于<template>
的name
属性值,React的组件名必须首字母大写,Omi的组件首字母不能大写,并且名字中间必须有-
符号连接。
React | Omi |
---|---|
<template name="ComponentName"> | <template name="component-name"> |
组件名必须首字母大写 | 组件首字母不能大写,并且名字中间必须有- 符号连接 |
在下面的例子中,我们声明了一个名为 title 的变量,然后在 JSX 中使用它,并将它包裹在大括号中:
<templatename="component-name"><div> {this.data.title}</div></template><script>exportdefaultclass{install(){this.data={title:"Eno Yao !"}}}</script>
在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式。例如,2 + 2,user.firstName 或 formatName(user) 都是有效的 JavaScript 表达式。
<templatename="component-name"><div><p>Name: {this.formatName(user)}</p><p>Age: {9+9}</p></div></template><script>constuser={firstName:'Eno',lastName:'Yao'};exportdefaultclass{formatName(user){returnuser.firstName+' '+user.lastName;}}</script>
二元和三元表达式
<templatename="component-name"><div> { !0 ? '真' :<p>假</p> }<h1>{ user.age> 18 &&<div>成年</div> }<h1></h1></div></template>
数组渲染成列表
<templatename="component-name"><ul> { ['a','b','c'].map((item,index) => { return<likey={index}>{item}</li> }) }</ul></template>
在编译之后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后得到 JavaScript 对象。
也就是说,你可以在 if 语句和 for 循环的代码块中使用 JSX,将 JSX 赋值给变量,把 JSX 当作参数传入,以及从函数中返回 JSX:
<templatename="component-name"><div><p>{this.getGreeting(user)}</p><p>{this.getGreeting()}</p></div></template><script>constuser={firstName:'Eno',lastName:'Yao'};exportdefaultclass{formatName(user){returnuser.firstName+' '+user.lastName;}getGreeting(user){if(user){return<h1>Hello,{this.formatName(user)}!</h1>;}return<h1>Hello, Stranger.</h1>;}}</script>
你可以通过使用引号,来将属性值指定为字符串字面量
<templatename="component-name"><divtabIndex="0"></div></template>
也可以使用大括号,来在属性值中插入一个 JavaScript 表达式:
<templatename="component-name"><divtabIndex="0"><imgsrc={this.data.avatarUrl}/></div></template><script>exportdefaultclass{install(){this.data={avatarUrl:'https://avatars1.githubusercontent.com/u/17243165?s=460&v=4'}}}</script>
HTML 和 JSX 的一些区别
HTML | JSX |
---|---|
<div class> | <div className> |
<label for> | <label htmlFor> |
<div tabindex> | <div tabIndex> |
在属性中嵌入 JavaScript 表达式时,不要在大括号外面加上引号。你应该仅使用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号。
警告:
因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。
例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex。
假如一个标签里面没有内容,你可以使用/>
来闭合标签,就像 XML 语法一样:
<imgsrc={this.data.avatarUrl}/><inputonChange={this.getInputValue.bind(this)}/>
JSX 标签里能够包含很多子元素:
<templatename="component-name"><div>{this.data.element}</div></template><script>exportdefaultclass{install(){this.data={element:(<div><h1>Hello!</h1><h2>Good to see you here.</h2></div>)}}}</script>
Babel 会把 JSX 转译成一个名为h()
函数调用。
以下两种示例代码完全等效:
constelement=<div><h1className="greeting"> Hello, world!</h1></div>
constelement=h("div",null,h("h1",{className:"greeting"},"Hello, world!"));
h()
会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
// 注意:这是简化过的结构constelement={children:[{attributes:{className:"greeting"},children:["Hello, world!"],nodeName:"h1",}],nodeName:"div"}
这些对象它们描述了你希望在屏幕上看到的内容。Omi 通过读取这些对象,然后使用它们来构建 DOM 以及保持随时更新。
我们可以在组件的属性上传入属性值,通过传入属性值让组件接受外部的数据而更改自身的状态。
<component-namemyObj={{name: 'Eno Yao' }}/>
组件内部通过props接受即可:
<templatename="component-name"><p>{props.myObj.name}</p></template>
我们还可以通过static defaultProps
设置默认的props值和通过static propTypes
设置默认的props类型。
<templatename="component-name"><div><p>{props.name}</p><p>{props.age}</p></div></template><script>exportdefaultclass{staticdefaultProps={name:'Omi',age:18}staticpropTypes={name:String,age:Number}}</script>
Omi 元素的事件处理和 React 一样和 DOM 元素的很相似,但是有一点语法上的不同:
- Omi 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
<templatename="component-name"><div><buttononClick={this.onClick}>Hello Omi!</button><buttononClick={(evt)=> {alert('Hello Omi!')}}>Hello Omi!</button><buttononClick={onClick}>Hello Omi!</button></div></template><script>constonClick=(evt)=>{alert('Hello Omi!')}exportdefaultclass{onClick(evt){alert('Hello Omi!')}}</script>
你必须谨慎对待 JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定 this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined。
这并不是 React 特有的行为;这其实与 JavaScript 函数工作原理有关。通常情况下,如果你没有在方法后面添加 (),例如 onClick={this.handleClick},你应该为这个方法绑定 this。
<templatename="component-name"><div><buttononClick={this.onClick.bind(this)}>{this.data.title}</button></div></template><script>exportdefaultclass{install(){this.data={title:'Hello Omi!'}}onClick(){this.data.title='Hi Eno!'this.update()}}</script>
在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:
<buttononClick={(e) => this.deleteRow(id, e)}>Delete Row</button><buttononClick={this.deleteRow.bind(this,id)}>Delete Row</button>
上述两种方式是等价的,分别通过箭头函数和 Function.prototype.bind 来实现。
在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。
以下表格是 Omi 的生命周期:
生命周期钩子 | 描述 |
---|---|
install | 组件挂载到 DOM 前 |
installed | 组件挂载到 DOM 后 |
uninstall | 组件从 DOM 中移除前 |
beforeUpdate | update 更新前 |
updated | update 更新后 |
beforeRender | render() 之前 |
receiveProps | 父元素重新渲染触发 |
举个例子:
<templatename="component-name"><div>Seconds: {this.data.seconds}</div></template><script>exportdefaultclass{data={seconds:0}tick(){this.data.seconds++this.update()}install(){this.interval=setInterval(()=>this.tick(),1000)}uninstall(){clearInterval(this.interval)}}</script>
update 方法是内置的重要核心方法,用于更新组件自身。比如:
this.update()
也可以传递参数,决定是否在 html 模式下忽略 attributes,强行更新:
this.update(true)
当我们组件的 data 值发生变化,我们可以使用this.update()
更新视图
<templatename="component-name"><div><buttononClick={this.toggle.bind(this)}>Update</button><pstyle={{display:this.data.bool?'block':'none'}}>显示或者隐藏</p></div></template><script>exportdefaultclass{data={bool:!0}toggle(){this.data.bool=!this.data.boolthis.update()}}</script>
<templatename="component-name"><div><h1ref={e=> { this.h1 = e }} onClick={this.onClick}>Hello, world!</h1></div></template><script>exportdefaultclass{onClick=(evt)=>{console.log(this.h1)}}</script>
在元素上添加ref={e => { this.anyNameYouWant = e }}
,然后你就可以 JS 代码里使用this.anyNameYouWant
访问该元素。你可以使用两种方式来提高 update 的性能:
- 提前赋值
- createRef
<templatename="component-name"><div><h1ref={e=> { this.myRef = e }} onClick={this.onClick}>Hello, world!</h1></div></template><script>exportdefaultclass{myRef=e=>{this.h1=e}onClick=(evt)=>{console.log(this.h1)}}</script>
你也可以使用createRef
来得到更高的性能,使用前需要引用import { createRef } from "omi"
:
<templatename="component-name"><div><h1ref={this.myRef}onClick={this.onClick}>Hello, world!</h1></div></template><script>import{createRef}from"omi";exportdefaultclass{myRef=createRef()onClick=(evt)=>{console.log(this.myRef.current)}}</script>
Store 是 Omi 内置的中心化数据仓库,他解决和提供了下面问题和能力:
组件树数据共享数据变更按需更新依赖的组件
path/elements/app/index.omi
下的根组件
<templatename="my-app"><div><p> Clicked: {this.use.count} times {' '}<buttononClick={this.add}>+</button> {' '}<buttononClick={this.sub}>-</button> {' '}<buttononClick={this.addIfOdd}> Add if odd</button> {' '}<buttononClick={this.addAsync}> Add async</button></p></div></template><script>exportdefaultclass{staticuse=[{count:'count'}]add=()=>this.store.add()sub=()=>this.store.sub()addIfOdd=()=>{if(this.use.count%2!==0){this.store.add()}}addAsync=()=>{setTimeout(()=>this.store.add(),1000)}}</script><stylelang="scss">/* CSS */p {color:#58bc58 };</style>
path/src/index.js
全局的入口文件代码
import{render}from'omi'import'./elements/app'render(<my-app/>,'#root',{data:{count:0},sub(){this.data.count--},add(){this.data.count++},})
- 通过
static use
声明依赖的 path - store 通过 render 的第三个参数从根节点注入到所有组件。
Store 里的 data:
{count:0,arr:['china','tencent'],motto:'I love omi.',userInfo:{firstName:'dnt',lastName:'zhang',age:18}}
下面举一个复杂的use
例子:
staticuse=['count',//直接字符串,JSX 里可通过 this.use[0] 访问'arr[0]',//也支持 path,JSX 里可通过 this.use[1] 访问//支持 json{//alias,JSX 里可通过 this.use.reverseMotto 访问reverseMotto:['motto',//pathtarget=>target.split('').reverse().join('')//computed]},{name:'arr[1]'},//{ alias: path },JSX 里可通过 this.use.name 访问{//alias,JSX 里可通过 this.use.fullName 访问fullName:[['userInfo.firstName','userInfo.lastName'],//path array(firstName,lastName)=>firstName+lastName//computed]},]
下面看看 JSX 中使用:
......<template><div><buttononClick={this.sub}>-</button><span>{this.use[0]}</span><buttononClick={this.add}>+</button><div><span>{this.use[1]}</span><buttononClick={this.rename}>rename</button></div><div>{this.use.reverseMotto}</div><buttononClick={this.changeMotto}>change motto</button><div>{this.use.name}</div><div>{this.use[3]}</div><div>{this.use.fullName}<buttononClick={this.changeFirstName}>change first name</button></div></div></template>......
如果不带有 alias ,你也可以直接通过this.store.data.xxx
访问。
当store.data
发生变化,依赖变更数据的组件会进行更新,举例说明 Path 命中规则:
Proxy Path(由数据更改产生) | static use 中的 path | 是否更新 |
---|---|---|
abc | abc | 更新 |
abc[1] | abc | 更新 |
abc.a | abc | 更新 |
abc | abc.a | 不更新 |
abc | abc[1] | 不更新 |
abc | abc[1].c | 不更新 |
abc.b | abc.b | 更新 |
以上只要命中一个条件就可以进行更新!
总结: 只要注入组件的 path 等于 use 里声明 或者在 use 里声明的其中 path 子节点下就会进行更新!
这里说的是 props 的 css,而不是 static css,它提供了修改 shadow dom 内部 scoped style 的能力。
<templatename="component-name"><div><h1>Look at my color!</h1></div></template><script>exportdefaultclass{staticcss=`h1{ color: red; }`}</script>
上面的my-element
的 h1 标签颜色是红色。有什么办法修改吗?
<templatename="component-name"><divonClick={this.onClick}><my-elementcss={this.myCSS}/></div></template><script>exportdefaultclass{myCSS=` h1{ color: green; } `onClick=()=>{//动态修改this.myCSS=` h1{ color: blue; } `this.update()}}</script>
而且还可以通过下面的方式保证一定能够修改:
color: blue!important;
如果您用过 React,相信对高阶组件肯定不陌生,高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
具体而言,高阶组件是参数为组件,返回值为新组件的函数。
constEnhancedComponent=higherOrderComponent(WrappedComponent);
组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件。
HOC 在 React 的第三方库中很常见,例如 Redux 的 connect。
下面这个例子是是在组件中使用 Redux 高阶组件
<templatename="Component-name"><div><p>{this.state.title}</p></div></template><script>import{connect}from'react-redux';exportdefaultconnect((state)=>{returnstate})(class{constructor(props){super(props)this.state={title:"react"}}})</script><style>p {color:#58bc58;}</style>