Omil
是一個 webpack 的 loader,它容許你以一種名爲單文件組件(SFCs)
的格式撰寫 Omi 組件:css
<template lang="html" name="component-name"> <header onClick="${this.test}">${this.data.title}</header> </template> <script> export default class { test(){ console.log('Hello Eno!') } install() { this.data = { title: 'Omi' } } } </script> <style> header { color: #58bc58; } </style>
Omil 還提供了不少酷炫的特性:html
<style>
的部分使用 Sass 和在<template>
的部分使用 jsx;<style>
和<template>
中引用的資源看成模塊依賴來處理;簡而言之,webpack 和 Omi Loader 的結合爲你提供了一個現代、靈活且極其強大的前端工做流,來幫助撰寫 Omi.js 應用。前端
若是你不想手動設置 webpack,咱們推薦使用 Omi CLI 直接建立一個項目的腳手架。經過 Omi CLI 建立的項目會針對多數常見的開發需求進行預先配置,作到開箱即用。node
若是Omi CLI
提供的內建沒有知足你的需求,或者你樂於從零開始建立你本身的 webpack 配置,那麼請繼續閱讀這篇指南。react
首先先安裝好Omil
webpack
npm install -D omil
若是你使用的是 Visual Studio Code 進行開發,強烈建議下載 Omi Snippets 擴展,它會提供給你語法高亮,局部編譯等功能。您能夠在 VSC 擴展界面裏面搜索 omi 這個關鍵詞出現Omi Snippets
點擊安裝便可,稍等片刻,當它安裝成功後會提醒你須要從新加載編輯工具,點擊從新加載便可使用。git
每一個Omil
包的新版本發佈時,一個相應版本的Omi Snippets
也會隨之發佈。github
Omi Loader 的配置和其它的 loader 基本同樣。web
// webpack.config.js module.exports = { module: { rules: [ // ... 其它規則 { test: /\.omi|eno$/, loader: 'omil' } ] } }
一個更完整的 webpack 配置示例看起來像這樣:npm
module.exports = { mode: 'development', module: { rules: [{ test: /\.omi|eno$/, use: [{ loader: require.resolve('omil'), options: { // Use in development, You should remove in production sourceMaps: 'both', // Config babel plugins for async, await and other many features plugins: [ [ "@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 後通過插件轉化的js文件 |
以下圖,左邊的代碼是咱們編寫的 .omi 後綴的單文件組件,右邊是通過 Omi Snippets 生成的 .js 後綴文件。
上圖的示例代碼以下
<template>
標籤負責放 JSX 的內容,屬性name="my-test"
爲該組件的名字,後面能夠在 JSX 中用<my-text>
使用該組件;<script>
標籤負責放入組件的邏輯文件,固定的結構爲 export default class { // 你的代碼 }
或者爲export default HOC(class { // 你的代碼 })
兩種形式,第一種是定義類組件,第二種用來定義高階組件,你的代碼部分能夠放入生命週期,函數等;<style>
標籤負責定義該組件的局部樣式<template name="my-test"> <div class="example"> { this.data.msg } </div> </template> <script> export default class { install () { this.data = { msg: 'Hello world!' } } } </script> <style> .example { color: red; } </style>
如下代碼就是通過 Omi Snippets 生成的 .js 後綴文件,能夠用於在你沒有 omil 模塊下,主邏輯文件或者其餘組件引入調用。
import { WeElement, define, h } from "omi"; class MyTest extends WeElement { render() { return h( "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 後綴文件處理爲 JS npm install omil --save-dev
在配置完 Omil 以後,咱們能夠在 VS Code 上同時安裝好 Omi Snippets 擴展,這個插件能夠方便的讓你把 .omi 和 .eno 後綴文件在未通過 webpack 處理前轉化爲 .js 文件,讓你能夠直觀瞭解到單文件組件通過 omil 轉化後的 JS 文件內容,這至關於局部編譯減輕 webpack 處理單文件時候的沒必要要消耗。
如今你可使用單文件組件來編寫 React 組件,默認生成類組件。
<template>
模板中不能有<script>
和<style>
代碼片斷。<template name="Component-name"> <div> <p>{this.state.title}</p> </div> </template> <script> export default class { constructor(props) { super(props) this.state = { title: "react" } } componentDidMount(){ console.log('生命週期') } } </script> <style> p {color: #58bc58}; </style>
以上文件通過 Omil 處理後將會轉化爲如下代碼:
import { Component as WeElement, createElement as h } from "react"; import styled from "styled-components"; const StyledComponents = styled.div` /* CSS */ p { color: #58bc58; } `; class ComponentName extends WeElement { render() { return h( 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}; `; export default ComponentName;
.omi 文件是一個自定義的文件類型,用類 HTML 語法描述一個 Omi 組件。每一個 .omi 文件包含三種類型的頂級語言塊 <template>
、<script>
和 <style>
:
<template name="my-test"> <div class="example"> { this.data.msg } </div> </template> <script> export default class { install () { this.data = { msg: 'Hello world!' } } } </script> <style> .example { color: red; } </style>
Omil 會解析文件,提取每一個語言塊,若有必要會經過其它 loader 處理,最後將他們組裝成一個 ES Module,它的默認導出是一個 Omi.js 組件定義好的自定義標籤對象。
Omil 支持使用非默認語言,好比 CSS 預處理器,預編譯的 HTML 模版語言,經過設置語言塊的 lang 屬性。例如,你能夠像下面這樣使用 Sass 語法編寫樣式:
<style lang="sass"> /* write Sass! */ </style>
<template>
模板每一個 .omi 文件最多包含一個 <template>
塊。
內容將被提取,若是是 JSX 會編譯爲函數片斷,若是爲 html 會編譯爲字符串,並最終注入到從<script>
導出的組件 render 函數中。
name = "xxx-xxx"
(Omi組件)定義name="xxx-xxx"
能夠給組件定義一個名字,這個名字會自動調用 omi 框架的 define('xxx-xxx', xxxXxx)
方法來註冊組件,你就能夠在頁面中用這個屬性名<xxx-xxx></xxx-xxx>
來使用該組件
注意:
-
字符;<template>
模板中不能有<script>
和<style>
代碼片斷。<template name="my-test"> <div class="example"> { this.data.msg } </div> </template>
在頁面容器中如此使用
<my-test/> <my-test></my-test>
name = "XxxXxx"
(React組件)定義name="XxxXxx"
能夠給組件定義一個名字,這個名字會自動調用 React 框架的 React.Component
方法來定義類組件,你就能夠在頁面中用這個屬性名<XxxXxx></XxxXxx>
來使用該組件
注意:
<template>
模板中不能有<script>
和<style>
代碼片斷。<template name="MyTest"> <div class="example"> { this.data.msg } </div> </template>
在頁面容器中如此使用
<MyTest/> <MyTest></MyTest>
lang = "html"
(僅支持Omi)默認狀況下,咱們的<template>
模板是使用 JSX 語法,若是咱們增長屬性lang = "html"
,就能夠支持編寫html格式的字符串模板,你可使用 ES6 的語法來編寫 html 模板<div>${ this.data.msg }<div>
,Omil 和 Omi-Snippets 會自動幫你引入Omi.html()
方法幫你在客戶端進行處理,會有必定的性能損耗,通常狀況下不建議使用。
<template name="my-test" lang="html"> <div class="example"> ${ this.data.msg } </div> </template>
<script>
腳本每一個 .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 { // 你的代碼 } <br/>export default MyText |
不能夠 | 不支持 |
class MyText { // 你的代碼 } <br/>module.export = MyText |
不能夠 | 不支持 |
<script> export default class { install () { this.data = { msg: 'Hello world!' } } } </script>
有時候咱們可使用高階組件拓展組件自己的一些功能,高階組件跟類組件同樣,只支持下面規定的寫法。
export default HOC(class { // 你的代碼 }) |
能夠 | 建議使用 |
---|---|---|
module.exports = HOC(class { // 你的代碼 }) |
能夠 | 支持 |
class MyText { // 你的代碼 } <br/>export default HOC(MyText) |
不能夠 | 不支持 |
class MyText { // 你的代碼 } <br/>module.export = HOC(MyText) |
不能夠 | 不支持 |
<script> export default HOC(class { install () { this.data = { msg: 'Hello world!' } } }) </script>
下面是一個高階組件的詳細參考例子
<template name="MyTest"> <div><p>{this.state.title}</p></div> </template> <script> // 高階函數 const HOC = (props) => { return (WraooedComponent) => { return class HOC extends WeElement { render() { return (<div><WraooedComponent name={{ ...this.props }} /></div>) } } } } export default HOC({ age: 18 })(class { install () { this.data = { msg: 'Hello world!' } } }) </script> <style lang="scss"> p { color: #58bc58; } </style>
或者你能夠這樣寫
<template name="MyTest"> {HOC(<div><p>{this.state.title}</p></div>)} </template> <script> // 高階函數 const HOC = (props) => { return (WraooedComponent) => { return class HOC extends WeElement { render() { return (<div><WraooedComponent name={{ ...this.props }} /></div>) } } } } export default class { install () { this.data = { msg: 'Hello world!' } } } </script> <style lang="scss"> p { color: #58bc58; } </style>
type="text/babel"
一般狀況下,你能夠在代碼中使用ES6的語法,甚至一些新特性,例如:static
,某些狀況下咱們須要轉化爲ES5作兼容,咱們能夠添加屬性type="text/babel"
<script> export default class { static name = 'Eno Yao' install () { this.data = { msg: 'Hello world!' } } } </script>
<style>
樣式一個 .omi 文件能夠包含一個<style>
標籤。
<style>
標籤的樣式自己具備局部樣式的特性,這取決於 Omi 的設計是 Web Components,這有點相似於 Vue 的 scoped 屬性。
<style> .example { color: red; } </style>
lang = "scss"
咱們還可使用lang = "scss"
來書寫 scss 樣式,它會自動幫咱們編譯爲 css 格式內容
<style lang = "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 --> |
觀察下面這段代碼模板:
<template name="component-name"> <header onClick={this.test}>{this.data.title}</header> </template>
這個有趣的標籤語法既不是字符串也不是 HTML。
它被稱爲 JSX,是一個 JavaScript 的語法擴展。咱們建議在 Omi 中配合使用 JSX,JSX 能夠很好地描述 UI 應該呈現出它應有交互的本質形式。JSX 可能會令人聯想到模版語言,但它具備 JavaScript 的所有功能。
上面的代碼事實上會自動編譯爲下面這份 js 代碼
import { WeElement, define, h } from "omi"; class ComponentName extends WeElement { render() { return h( "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 中使用它,並將它包裹在大括號中:
<template name="component-name"> <div> {this.data.title} </div> </template> <script> export default class { install() { this.data = { title: "Eno Yao !" } } } </script>
在 JSX 語法中,你能夠在大括號內放置任何有效的 JavaScript 表達式。例如,2 + 2,user.firstName 或 formatName(user) 都是有效的 JavaScript 表達式。
<template name="component-name"> <div> <p>Name: {this.formatName(user)}</p> <p>Age: {9+9}</p> </div> </template> <script> const user = { firstName: 'Eno', lastName: 'Yao' }; export default class { formatName(user) { return user.firstName + ' ' + user.lastName; } } </script>
二元和三元表達式
<template name="component-name"> <div> { !0 ? '真' : <p>假</p> } <h1>{ user.age > 18 && <div>成年</div> }<h1></h1> </div> </template>
數組渲染成列表
<template name="component-name"> <ul> { ['a','b','c'].map((item,index) => { return <li key={index}>{item}</li> }) } </ul> </template>
在編譯以後,JSX 表達式會被轉爲普通 JavaScript 函數調用,而且對其取值後獲得 JavaScript 對象。
也就是說,你能夠在 if 語句和 for 循環的代碼塊中使用 JSX,將 JSX 賦值給變量,把 JSX 看成參數傳入,以及從函數中返回 JSX:
<template name="component-name"> <div> <p>{this.getGreeting(user)}</p> <p>{this.getGreeting()}</p> </div> </template> <script> const user = { firstName: 'Eno', lastName: 'Yao' }; export default class { formatName(user) { return user.firstName + ' ' + user.lastName; } getGreeting(user) { if (user) { return <h1>Hello, {this.formatName(user)}!</h1>; } return <h1>Hello, Stranger.</h1>; } } </script>
你能夠經過使用引號,來將屬性值指定爲字符串字面量
<template name="component-name"> <div tabIndex="0"></div> </template>
也可使用大括號,來在屬性值中插入一個 JavaScript 表達式:
<template name="component-name"> <div tabIndex="0"> <img src={this.data.avatarUrl} /> </div> </template> <script> export default class { 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 語法同樣:
<img src={this.data.avatarUrl} /> <input onChange={this.getInputValue.bind(this)} />
JSX 標籤裏可以包含不少子元素:
<template name="component-name"> <div>{this.data.element}</div> </template> <script> export default class { install() { this.data = { element: ( <div> <h1>Hello!</h1> <h2>Good to see you here.</h2> </div> ) } } } </script>
Babel 會把 JSX 轉譯成一個名爲 h()
函數調用。
如下兩種示例代碼徹底等效:
const element = <div> <h1 className="greeting"> Hello, world! </h1> </div>
const element = h( "div", null, h( "h1", { className: "greeting" }, "Hello, world!" ) );
h()
會預先執行一些檢查,以幫助你編寫無錯代碼,但實際上它建立了一個這樣的對象:
// 注意:這是簡化過的結構 const element = { children: [{ attributes: {className: "greeting"}, children: ["Hello, world!"], nodeName: "h1", }], nodeName: "div" }
這些對象它們描述了你但願在屏幕上看到的內容。Omi 經過讀取這些對象,而後使用它們來構建 DOM 以及保持隨時更新。
咱們能夠在組件的屬性上傳入屬性值,經過傳入屬性值讓組件接受外部的數據而更改自身的狀態。
<component-name myObj={{ name: 'Eno Yao' }} />
組件內部經過props接受便可:
<template name="component-name"> <p>{props.myObj.name}</p> </template>
咱們還能夠經過static defaultProps
設置默認的props值和經過static propTypes
設置默認的props類型。
<template name="component-name"> <div> <p>{props.name}</p> <p>{props.age}</p> </div> </template> <script> export default class { static defaultProps = { name: 'Omi', age: 18 } static propTypes = { name: String, age: Number } } </script>
Omi 元素的事件處理和 React 同樣和 DOM 元素的很類似,可是有一點語法上的不一樣:
<template name="component-name"> <div> <button onClick={this.onClick}>Hello Omi!</button> <button onClick={(evt)=> {alert('Hello Omi!')}}>Hello Omi!</button> <button onClick={onClick}>Hello Omi!</button> </div> </template> <script> const onClick = (evt) => { alert('Hello Omi!') } export default class { onClick(evt) { alert('Hello Omi!') } } </script>
你必須謹慎對待 JSX 回調函數中的 this,在 JavaScript 中,class 的方法默認不會綁定 this。若是你忘記綁定 this.handleClick 並把它傳入了 onClick,當你調用這個函數的時候 this 的值爲 undefined。
這並非 React 特有的行爲;這其實與 JavaScript 函數工做原理有關。一般狀況下,若是你沒有在方法後面添加 (),例如 onClick={this.handleClick},你應該爲這個方法綁定 this。
<template name="component-name"> <div> <button onClick={this.onClick.bind(this)}>{this.data.title}</button> </div> </template> <script> export default class { install() { this.data = { title: 'Hello Omi!' } } onClick() { this.data.title = 'Hi Eno!' this.update() } } </script>
在循環中,一般咱們會爲事件處理函數傳遞額外的參數。例如,若 id 是你要刪除那一行的 ID,如下兩種方式均可以向事件處理函數傳遞參數:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={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 | 父元素從新渲染觸發 |
舉個例子:
<template name="component-name"> <div>Seconds: {this.data.seconds}</div> </template> <script> export default class { 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()
更新視圖
<template name="component-name"> <div> <button onClick={this.toggle.bind(this)}>Update</button> <p style={{display:this.data.bool?'block':'none'}}>顯示或者隱藏</p> </div> </template> <script> export default class { data = { bool: !0 } toggle() { this.data.bool = !this.data.bool this.update() } } </script>
<template name="component-name"> <div> <h1 ref={e=> { this.h1 = e }} onClick={this.onClick}>Hello, world!</h1> </div> </template> <script> export default class { onClick = (evt) => { console.log(this.h1) } } </script>
在元素上添加 ref={e => { this.anyNameYouWant = e }}
,而後你就能夠 JS 代碼裏使用 this.anyNameYouWant
訪問該元素。你可使用兩種方式來提升 update 的性能:
<template name="component-name"> <div> <h1 ref={e=> { this.myRef = e }} onClick={this.onClick}>Hello, world!</h1> </div> </template> <script> export default class { myRef = e => { this.h1 = e } onClick = (evt) => { console.log(this.h1) } } </script>
你也可使用 createRef
來獲得更高的性能,使用前須要引用 import { createRef } from "omi"
:
<template name="component-name"> <div> <h1 ref={this.myRef} onClick={this.onClick}>Hello, world!</h1> </div> </template> <script> import { createRef } from "omi"; export default class { myRef = createRef() onClick = (evt) => { console.log(this.myRef.current) } } </script>
Store 是 Omi 內置的中心化數據倉庫,他解決和提供了下面問題和能力:
組件樹數據共享
數據變動按需更新依賴的組件
path/elements/app/index.omi
下的根組件
<template name="my-app"> <div> <p> Clicked: {this.use.count} times {' '} <button onClick={this.add}>+</button> {' '} <button onClick={this.sub}>-</button> {' '} <button onClick={this.addIfOdd}> Add if odd </button> {' '} <button onClick={this.addAsync}> Add async </button> </p> </div> </template> <script> export default class { static use = [ { 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> <style lang="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
聲明依賴的 pathStore 裏的 data:
{ count: 0, arr: ['china', 'tencent'], motto: 'I love omi.', userInfo: { firstName: 'dnt', lastName: 'zhang', age: 18 } }
下面舉一個複雜的 use
例子:
static use = [ 'count', //直接字符串,JSX 裏可經過 this.use[0] 訪問 'arr[0]', //也支持 path,JSX 裏可經過 this.use[1] 訪問 //支持 json { //alias,JSX 裏可經過 this.use.reverseMotto 訪問 reverseMotto: [ 'motto', //path target => 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> <button onClick={this.sub}>-</button> <span>{this.use[0]}</span> <button onClick={this.add}>+</button> <div> <span>{this.use[1]}</span> <button onClick={this.rename}>rename</button> </div> <div>{this.use.reverseMotto}</div><button onClick={this.changeMotto}>change motto</button> <div>{this.use.name}</div> <div>{this.use[3]}</div> <div> {this.use.fullName} <button onClick={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 的能力。
<template name="component-name"> <div> <h1>Look at my color!</h1> </div> </template> <script> export default class { static css = `h1{ color: red; }` } </script>
上面的 my-element
的 h1 標籤顏色是紅色。有什麼辦法修改嗎?
<template name="component-name"> <div onClick={this.onClick}> <my-element css={this.myCSS} /> </div> </template> <script> export default class { myCSS = ` h1{ color: green; } ` onClick = () => { //動態修改 this.myCSS = ` h1{ color: blue; } ` this.update() } } </script>
並且還能夠經過下面的方式保證必定可以修改:
color: blue!important;
若是您用過 React,相信對高階組件確定不陌生,高階組件(HOC)是 React 中用於複用組件邏輯的一種高級技巧。HOC 自身不是 React API 的一部分,它是一種基於 React 的組合特性而造成的設計模式。
具體而言,高階組件是參數爲組件,返回值爲新組件的函數。
const EnhancedComponent = higherOrderComponent(WrappedComponent);
組件是將 props 轉換爲 UI,而高階組件是將組件轉換爲另外一個組件。
HOC 在 React 的第三方庫中很常見,例如 Redux 的 connect。
下面這個例子是是在組件中使用 Redux 高階組件
<template name="Component-name"> <div><p>{this.state.title}</p></div> </template> <script> import { connect } from 'react-redux'; export default connect((state) => { return state })(class { constructor(props) { super(props) this.state = { title: "react" } } }) </script> <style> p {color: #58bc58;} </style>