Merge pull request #1 from Tencent/master

update
This commit is contained in:
LLLLL 2018-11-06 21:03:13 +08:00 committed by GitHub
commit cbd2b51c2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 4166 additions and 1600 deletions

View File

@ -15,7 +15,7 @@
- [**Web Components**](https://developers.google.com/web/fundamentals/web-components/) + [**JSX**](https://reactjs.org/docs/introducing-jsx.html) 相互融合为一个框架 Omi
- 内置 observe 制作响应式视图(免去 `this.update`)
- Web Components 也可以数据驱动视图, `UI = fn(data)`
- JSX 是开发体验最棒(智能提示)、[语法噪音最少](https://github.com/facebook/jsx#why-not-template-literals)、图灵完备的 UI 表达式
- JSX 是开发体验最棒(智能提示)、[语法噪音最少](https://github.com/facebook/jsx#why-not-template-literals)、图灵完备的 UI 表达式,模板引擎不完备,模板字符串完备但是语法噪音太大
- 独创的 `Path Updating` 机制,基于 Proxy 全自动化的精准更新,功耗低,自由度高,性能卓越,方便集成 `requestIdleCallback`
- 对 this.update 说再见吧!只要使用 `store` 系统,它就会自动化按需更新局部视图
- 看看[Facebook React 和 Web Components对比优势](https://www.cnblogs.com/rubylouvre/p/4072979.html)Omi 融合了各自的优点,而且给开发者自由的选择喜爱的方式
@ -48,10 +48,26 @@
| [omi-native](https://github.com/Tencent/omi/tree/master/packages/omi-native)|把 web components 渲染到 native比如 IOS 、Android|
|[omi element ui(working)](https://github.com/Tencent/omi/tree/master/packages/omi-element-ui)|Omi 版本的 element-ui|
|[westore](https://github.com/dntzhang/westore)|小程序解决方案 westore与 Omi 互相启发|
| [omi-weui(working)](https://github.com/Tencent/omi/tree/master/packages/omi-weui)|Weui for Omi.|
## 必须收藏的资源
* [Web Components MDN](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components)
* [Web Components Google](https://developers.google.com/web/fundamentals/web-components/)
* [Web Components Org](https://www.webcomponents.org/introduction)
* [Proxy MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
* [https://www.webcomponents.org/](https://www.webcomponents.org/)
* [https://www.webcomponents.org/elements](https://www.webcomponents.org/elements)
* [CSS Variables](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_variables)
* [CSS Shadow Parts](https://drafts.csswg.org/css-shadow-parts-1/)
* [Part Theme Explainer](https://meowni.ca/posts/part-theme-explainer/)
---
# 目录
- [Omi 生态](#omi-生态)
- [必须收藏的资源](#必须收藏的资源)
- [一个 HTML 完全上手](#一个-html-完全上手)
- [再花 30 秒完全上手](#再花-30-秒完全上手)
- [快速入门](#快速入门)
@ -69,7 +85,6 @@
- [相关链接](#相关链接)
- [贡献代码](#贡献代码)
- [感谢](#感谢)
- [Web Components 资源](#web-components-资源)
- [License](#license)
## 一个 HTML 完全上手
@ -699,15 +714,6 @@ Omi 4.0+ works in the latest two versions of all major browsers: Safari 10+, IE
* [preact](https://github.com/developit/preact)
* [JSONPatcherProxy](https://github.com/Palindrom/JSONPatcherProxy)
## Web Components 资源
* [Web Components MDN](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components)
* [Web Components Google](https://developers.google.com/web/fundamentals/web-components/)
* [Web Components Org](https://www.webcomponents.org/introduction)
* [Proxy MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
* [https://www.webcomponents.org/](https://www.webcomponents.org/)
* [https://www.webcomponents.org/elements](https://www.webcomponents.org/elements)
## License
MIT © Tencent

View File

@ -50,9 +50,22 @@ Omi는 Shadow DOM 기반 스타일 분기 및 시멘틱 구조를 사용합니
| [omi-native](https://github.com/Tencent/omi/tree/master/packages/omi-native)| Web Components Native 렌더링 |
| [omi element ui(working)](https://github.com/Tencent/omi/tree/master/packages/omi-element-ui)| Omi 버전의 element-ui |
## Useful Resources
* [Web Components MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components)
* [Web Components Google](https://developers.google.com/web/fundamentals/web-components/)
* [Web Components Org](https://www.webcomponents.org/introduction)
* [Proxy MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
* [https://www.webcomponents.org/](https://www.webcomponents.org/)
* [https://www.webcomponents.org/elements](https://www.webcomponents.org/elements)
* [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables)
* [CSS Shadow Parts](https://drafts.csswg.org/css-shadow-parts-1/)
* [Part Theme Explainer](https://meowni.ca/posts/part-theme-explainer/)
---
- [Ecosystem of Omi](#ecosystem-of-omi)
- [Useful Resources](#useful-resources)
- [Omi 1분 추가 가이드](#Omi-1분-추가-가이드)
- [Omi 30초 추가 가이드](#Omi-30초-추가-가이드)
- [Getting Started](#getting-started)
@ -66,10 +79,10 @@ Omi는 Shadow DOM 기반 스타일 분기 및 시멘틱 구조를 사용합니
- [Omi Mobx](#omi-mobx)
- [Lifecycle](#lifecycle)
- [Debugging](#debugging)
- [React to Omi](#react-to-omi)
- [Browsers Support](#browsers-support)
- [Contribution](#contribution)
- [Thanks](#thanks)
- [Web Components Resource](#web-components-resource)
- [License](#license)
## Omi 1분 추가 가이드
@ -634,34 +647,16 @@ Omi는 Web Components 와 Shadow-DOM을 사용하기 때문에 React 및 Vue 처
![Omi DevTools](https://github.com/f/omi-devtools/raw/master/omi-devtools.gif)
## Omi Mobx
## React to Omi
당신은 store 시스템을 버리고, omi-mobx를 사용하여 반응형 뷰를 만들수 있습니다:
예를들면, 아래는 weui React 의 button 을 weui Omi의 button 으로 마이그레이션 하는 예제 입니다:
```js
import { tag, WeElement } from "omi";
import { observe } from "omi-mobx";
![react to omi](./assets/react-to-omi.png)
@observe
@tag("my-app")
class MyApp extends WeElement {
install() {
this.data.name = "omi";
}
onClick = () => {
this.data.name = "Omi V4.0";
};
render(props, data) {
return (
<div onClick={this.onClick}>
<h1>Welcome to {data.name}</h1>
</div>
);
}
}
```
* [Diff Split](https://github.com/Tencent/omi/commit/9790fadaaf20cfede80bcf9213756a83fc8c3949?diff=split)
* [Diff Unified](https://github.com/Tencent/omi/commit/9790fadaaf20cfede80bcf9213756a83fc8c3949?diff=unified)
* [Before](https://github.com/Tencent/omi/blob/c8af654f1d5865dc557c0b4b8ad524f702a69be5/packages/omi-weui/src/omi-weui/elements/button/button.js)
* [After](https://github.com/Tencent/omi/blob/9790fadaaf20cfede80bcf9213756a83fc8c3949/packages/omi-weui/src/omi-weui/elements/button/button.js)
## Browsers Support
@ -697,15 +692,6 @@ Please contact us for any questions:
* [preact](https://github.com/developit/preact)
* [JSONPatcherProxy](https://github.com/Palindrom/JSONPatcherProxy)
## Web Components Resource
* [Web Components MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components)
* [Web Components Google](https://developers.google.com/web/fundamentals/web-components/)
* [Web Components Org](https://www.webcomponents.org/introduction)
* [Proxy MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
* [https://www.webcomponents.org/](https://www.webcomponents.org/)
* [https://www.webcomponents.org/elements](https://www.webcomponents.org/elements)
## License
MIT © Tencent

View File

@ -15,7 +15,7 @@ English | [简体中文](./README.CN.md) | [한국어](./README.KR.md)
- Merge [**Web Components**](https://developers.google.com/web/fundamentals/web-components/) and [**JSX**](https://reactjs.org/docs/introducing-jsx.html) into one framework.
- Built in observe feature (No need to call `this.update()`).
- Web Components can also be a data-driven view, **`UI = fn(data)`**.
- JSX is the best development experience (code intelligent completion and tip) UI Expression with least [grammatical noise](https://github.com/facebook/jsx#why-not-template-literals) and it's turing complete(template engine is not).
- JSX is the best development experience (code intelligent completion and tip) UI Expression with least [grammatical noise](https://github.com/facebook/jsx#why-not-template-literals) and it's turing complete(template engine is not, es template string is but grammatical noise is too loud).
- The original **Path Updating** system. Proxy-based automatic **accurate** update, **low power consumption**, high degree of freedom, excellent performance, easy integration of `requestIdleCallback`
- Say goodbye to `this.update` method when using **store system**! It will automatically update UI partially when data is changed.
- Look at [Facebook React vs Web Components](https://softwareengineering.stackexchange.com/questions/225400/pros-and-cons-of-facebooks-react-vs-web-components-polymer)Omi **combines their advantages** and gives developers the **freedom to choose the way they like**.
@ -49,10 +49,26 @@ Omi uses Shadow DOM based style isolation and semantic structure.
| [omi-use](https://github.com/Tencent/omi/blob/master/docs/main-concepts.md#use)|React hooks like API|
| [omi-native](https://github.com/Tencent/omi/tree/master/packages/omi-native)|Render web components to native|
|[omi element ui(working)](https://github.com/Tencent/omi/tree/master/packages/omi-element-ui)|Omi version of element-ui|
| [omi-weui(working)](https://github.com/Tencent/omi/tree/master/packages/omi-weui)|Weui for Omi.|
## Useful Resources
* [Web Components MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components)
* [Web Components Google](https://developers.google.com/web/fundamentals/web-components/)
* [Web Components Org](https://www.webcomponents.org/introduction)
* [Proxy MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
* [https://www.webcomponents.org/](https://www.webcomponents.org/)
* [https://www.webcomponents.org/elements](https://www.webcomponents.org/elements)
* [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables)
* [CSS Shadow Parts](https://drafts.csswg.org/css-shadow-parts-1/)
* [Part Theme Explainer](https://meowni.ca/posts/part-theme-explainer/)
---
# Overview of the Readme
- [Ecosystem of Omi](#ecosystem-of-omi)
- [Useful Resources](#useful-resources)
- [Add Omi in One Minute](#add-omi-in-one-minute)
- [Add Omi in 30 Seconds](#add-omi-in-30-seconds)
- [Getting Started](#getting-started)
@ -70,7 +86,6 @@ Omi uses Shadow DOM based style isolation and semantic structure.
- [Browsers Support](#browsers-support)
- [Contribution](#contribution)
- [Thanks](#thanks)
- [Web Components Resource](#web-components-resource)
- [License](#license)
## Add Omi in One Minute
@ -655,7 +670,7 @@ Since Omi uses Web Components and Shadow-DOM, it doesn't need to have another el
## React to Omi
For example:
For example, the below is about migration React button as weui Omi button:
![react to omi](./assets/react-to-omi.png)
@ -698,15 +713,6 @@ Please contact us for any questions:
* [preact](https://github.com/developit/preact)
* [JSONPatcherProxy](https://github.com/Palindrom/JSONPatcherProxy)
## Web Components Resource
* [Web Components MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components)
* [Web Components Google](https://developers.google.com/web/fundamentals/web-components/)
* [Web Components Org](https://www.webcomponents.org/introduction)
* [Proxy MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
* [https://www.webcomponents.org/](https://www.webcomponents.org/)
* [https://www.webcomponents.org/elements](https://www.webcomponents.org/elements)
## License
MIT © Tencent

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/css3transform.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -8,6 +8,7 @@
- [Event](#event)
- [Custom Event](#custom-event)
- [CSS](#css)
- [Lifecycle](#lifecycle)
- [Ref](#ref)
- [Store](#store)
- [Slot](#slot)
@ -188,6 +189,49 @@ define('el-button', class extends WeElement {
...
```
### Lifecycle
| Lifecycle method | When it gets called |
| ---------------- | -------------------------------------------- |
| `install` | before the component gets mounted to the DOM |
| `installed` | after the component gets mounted to the DOM |
| `uninstall` | prior to removal from the DOM |
| `beforeUpdate` | before update |
| `afterUpdate` | after update |
| `beforeRender` | before `render()` |
For example:
```js
import { render, WeElement, define } from 'omi'
define('my-timer', class extends WeElement {
static observe = true
data = {
seconds: 0
}
tick() {
this.data.seconds++
}
install() {
this.interval = setInterval(() => this.tick(), 1000)
}
uninstall() {
clearInterval(this.interval)
}
render() {
return <div>Seconds: {this.data.seconds}</div>
}
})
render(<my-timer />, 'body')
```
### Ref
```js

View File

@ -8,6 +8,7 @@ English | [简体中文](./main-concepts.cn.md) | [한국어](./main-concepts.kr
- [Event](#event)
- [Custom Event](#custom-event)
- [CSS](#css)
- [Lifecycle](#lifecycle)
- [Ref](#ref)
- [Store](#store)
- [Slot](#slot)
@ -202,6 +203,49 @@ define('el-button', class extends WeElement {
...
```
### Lifecycle
| Lifecycle method | When it gets called |
| ---------------- | -------------------------------------------- |
| `install` | before the component gets mounted to the DOM |
| `installed` | after the component gets mounted to the DOM |
| `uninstall` | prior to removal from the DOM |
| `beforeUpdate` | before update |
| `afterUpdate` | after update |
| `beforeRender` | before `render()` |
For example:
```js
import { render, WeElement, define } from 'omi'
define('my-timer', class extends WeElement {
static observe = true
data = {
seconds: 0
}
tick() {
this.data.seconds++
}
install() {
this.interval = setInterval(() => this.tick(), 1000)
}
uninstall() {
clearInterval(this.interval)
}
render() {
return <div>Seconds: {this.data.seconds}</div>
}
})
render(<my-timer />, 'body')
```
### Ref
```js

View File

@ -10,6 +10,7 @@
"babel-loader": "7.1.2",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.5",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-preset-omi": "^0.1.1",
"babel-runtime": "6.26.0",
@ -94,7 +95,8 @@
],
"plugins": [
"transform-class-properties",
"transform-decorators-legacy"
"transform-decorators-legacy",
"transform-object-rest-spread"
]
},
"prettier": {

View File

@ -36,15 +36,15 @@
| el-menu| @zhengbao |
| el-tabs| @zhengbao |
| ~~el-breadcrumb~~| @wadellg | [Usage](https://github.com/Tencent/omi/blob/master/packages/omi-element-ui/src/elements/breadcrumb/index.js)|
| el-dropdown| shijiezou |
| el-dropdown| [@jayZOU](https://github.com/jayZOU) |
| el-steps| @daizhan |
| el-dialog| shijiezou |
| el-dialog| [@jayZOU](https://github.com/jayZOU) |
| el-tooltip| |
| el-popover| |
| el-card| @wadellg |
| el-carousel| |
| el-collapse| |
| notice| | |
| notice| [@jayZOU](https://github.com/jayZOU) | |
## Develop

View File

@ -0,0 +1,7 @@
.group {
margin: 50px;
}
.group el-button{
margin-left: 20px;
}

View File

@ -0,0 +1,180 @@
import { tag, WeElement } from 'omi'
import style from './_index.css'
import notify from '../../omi-element-ui/el-notification'
import '../../omi-element-ui/el-button'
@tag('my-app')
class MyApp extends WeElement {
css() {
return style
}
open = () => {
notify({
title: '提示',
message: '这是一条自动关闭的消息'
})
}
open1 = () => {
notify({
title: '提示',
message: '这是一条不会自动关闭的消息',
duration: 0
})
}
open2 = () => {
notify({
title: '成功',
message: '这是一条成功的消息',
type: 'success'
})
}
open3 = () => {
notify({
title: '警告',
message: '这是一条警告的消息',
type: 'warning'
})
}
open4 = () => {
notify({
title: '消息',
message: '这是一条普通的消息',
type: 'info'
})
}
open5 = () => {
notify({
title: '错误',
message: '这是一条错误的消息',
type: 'error'
})
}
open6 = () => {
notify({
title: '消息',
message: '这是一条右上角的消息'
})
}
open7 = () => {
notify({
title: '消息',
message: '这是一条右下角的消息',
position: 'bottom-right'
})
}
open8 = () => {
notify({
title: '消息',
message: '这是一条左下角的消息',
position: 'bottom-left'
})
}
open9 = () => {
notify({
title: '消息',
message: '这是一条左上角的消息',
position: 'top-left'
})
}
open10 = () => {
notify({
title: '偏移消息',
message: '这是一条带偏移的消息',
offset: 100
})
}
open11 = () => {
notify({
title: 'HTML片段',
message: (
<strong>
这是 <i>HTML</i>
</strong>
)
})
}
open12 = () => {
notify({
title: '隐藏关闭按钮',
message: '这是一条隐藏关闭按钮的消息',
showClose: false
})
}
render(props, data) {
return (
<div>
<div class="group">
<el-button onClick={this.open} plain>
可自动关闭
</el-button>
<el-button onClick={this.open1} plain>
不会自动关闭
</el-button>
</div>
<div class="group">
<el-button onClick={this.open2} plain>
成功
</el-button>
<el-button onClick={this.open3} plain>
警告
</el-button>
<el-button onClick={this.open4} plain>
消息
</el-button>
<el-button onClick={this.open5} plain>
错误
</el-button>
</div>
<div class="group">
<el-button onClick={this.open6} plain>
右上角
</el-button>
<el-button onClick={this.open7} plain>
右下角
</el-button>
<el-button onClick={this.open8} plain>
左下角
</el-button>
<el-button onClick={this.open9} plain>
左上角
</el-button>
</div>
<div class="group">
<el-button onClick={this.open10} plain>
偏移的消息
</el-button>
</div>
<div class="group">
<el-button onClick={this.open11} plain>
使用HTML片段
</el-button>
</div>
<div class="group">
<el-button onClick={this.open12} plain>
隐藏关闭按钮
</el-button>
</div>
</div>
)
}
}

View File

@ -0,0 +1,28 @@
import { tag, WeElement } from 'omi'
import '../../omi-element-ui/el-switch'
import style from './_index.css'
@tag('my-app', true)
class MyApp extends WeElement {
handleChange(value) {
console.log(value)
}
css() {
return style
}
render() {
return (
<el-switch
style="display: block"
active-color="#13ce66"
inactive-color="#ff4949"
active-text="按月付费"
inactive-text="按年付费"
false-value="年"
width="80"
onChange={this.handleChange}
/>
)
}
}

View File

@ -1,2 +1,2 @@
//you can change this to debug your elemnts
location.href = 'alert.html'
location.href = 'switch.html'

View File

@ -0,0 +1,5 @@
import { render } from 'omi'
import './assets/index.css'
import './elements/notification'
render(<my-app />, '#root')

View File

@ -0,0 +1,72 @@
import { render, define, getHost } from 'omi'
import '../style/global/index.css'
import notification from '../style/_notification.scss'
import icon from '../../omi-element-ui/style/global/_icon.scss'
const offsetHeight = 94
define('el-notification', props => {
let notifiDom = document.querySelectorAll(
`el-notification[type="${props.ops.position}"]`
)
let closeBtn = null
let position = props.ops.position.split('-')
const close = evt => {
document.body.removeChild(getHost(evt.currentTarget || evt.parentNode))
notifiDom = document.querySelectorAll(
`el-notification[type="${props.ops.position}"]`
)
for (let i = 0; i < notifiDom.length; i++) {
notifiDom[i].host[1].style[position[0]] = `${offsetHeight * i +
props.ops.offset}px`
}
}
if (props.ops.duration !== 0) {
setTimeout(() => {
close(closeBtn)
}, 4500)
}
return [
<style>{notification + icon}</style>,
<div
class={`el-notification ${position[1]}`}
style={`${position[0]}: ${offsetHeight * (notifiDom.length - 1) +
props.ops.offset}px; z-index: 2129;`}
>
{props.ops.type && (
<i class={`el-notification__icon el-icon-${props.ops.type}`} />
)}
<div
class={`el-notification__group ${props.ops.type ? 'is-with-icon' : ''}`}
>
<h2 class="el-notification__title">{props.ops.title}</h2>
<div class="el-notification__content">
<p>{props.ops.message}</p>
</div>
{props.ops.showClose ? (
<div
ref={e => (closeBtn = e)}
class="el-notification__closeBtn el-icon-close"
onClick={evt => close(evt)}
/>
) : (
<div ref={e => (closeBtn = e)} />
)}
</div>
</div>
]
})
const Notification = function(opts) {
opts.position = opts.position || 'top-right'
opts.offset = opts.offset || 16
opts.showClose = opts.showClose === false ? false : true
render(<el-notification type={opts.position} ops={opts} />, document.body)
}
export default Notification

View File

@ -0,0 +1,121 @@
import { tag, WeElement } from 'omi'
import '../style/global/index.css'
import style from '../style/_switch.scss'
@tag('el-switch', true)
class ElSwitch extends WeElement {
static observe = true
data = {
value: null,
checked: true
}
css() {
return style
}
switchValue = () => {
!this.props.disabled && this.handleChange()
}
handleChange = () => {
this.data.checked = !this.data.checked
const trueValue = this.props.hasOwnProperty('trueValue') ? this.props.trueValue : true // eslint-disable-line
const falseValue = this.props.hasOwnProperty('falseValue') ? this.props.falseValue : true // eslint-disable-line
this.fire('input', this.data.checked ? trueValue : falseValue)
this.fire('change', this.data.checked ? trueValue : falseValue)
this.domInput.checked = this.data.checked
}
installed() {
if (!this.mo) {
this.mo = new MutationObserver(() => {
if (this.domInput.checked !== this.data.checked) {
this.domInput.checked = this.data.checked
}
})
this.mo.observe(this.domInput, { attributes: true })
}
}
handleKeyUp = e => {
if (e.keyCode === 32) {
this.switchValue()
}
}
render(props, data) {
const {
inactiveText,
activeText,
disabled,
activeValue = true,
inactiveValue = false,
width = 40,
activeColor,
inactiveColor,
id,
name
} = props
const { checked, switchDisabled } = data
const leftLabelClass = ['el-switch__label', 'el-switch__label--left']
const rightLabelClass = ['el-switch__label', 'el-switch__label--right']
if (data.checked) {
rightLabelClass.push('is-active')
} else {
leftLabelClass.push('is-active')
}
const wrapperClass = ['el-switch']
if (disabled) {
wrapperClass.push('is-disabled')
}
if (checked) {
wrapperClass.push('is-checked')
}
let coreColor = checked ? activeColor : inactiveColor
return (
<div
class={wrapperClass.join(' ')}
role="switch"
aria-checked={checked}
aria-disabled={switchDisabled}
onClick={this.switchValue}
>
<input
type="checkbox"
class="el-switch__input"
id={id}
name={name}
onChange={this.handleChange}
ref={e => {
this.domInput = e
}}
true-value={activeValue}
false-value={inactiveValue}
disabled={switchDisabled}
onKeyUp={this.handleKeyUp}
/>
{inactiveText && (
<span class={leftLabelClass.join(' ')}>
{<span aria-hidden={checked}>{inactiveText}</span>}
</span>
)}
<span
class="el-switch__core"
ref={e => {
this.domCore = e
}}
style={{
width: width + 'px',
borderColor: coreColor,
backgroundColor: coreColor
}}
/>
{activeText && (
<span class={rightLabelClass.join(' ')}>
{<span aria-hidden={!checked}>{activeText}</span>}
</span>
)}
</div>
)
}
}

View File

@ -0,0 +1,116 @@
@import "mixins/mixins";
@import "common/var";
@include b(switch) {
display: inline-flex;
align-items: center;
position: relative;
font-size: $--switch-font-size;
line-height: $--switch-height;
height: $--switch-height;
vertical-align: middle;
@include when(disabled) {
& .el-switch__core,
& .el-switch__label {
cursor: not-allowed;
}
}
@include e(label) {
transition: .2s;
height: $--switch-height;
display: inline-block;
font-size: $--switch-font-size;
font-weight: 500;
cursor: pointer;
vertical-align: middle;
color: $--color-text-primary;
@include when(active) {
color: $--color-primary;
}
@include m(left) {
margin-right: 10px;
}
@include m(right) {
margin-left: 10px;
}
& * {
line-height: 1;
font-size: $--switch-font-size;
display: inline-block;
}
}
@include e(input) {
position: absolute;
width: 0;
height: 0;
opacity: 0;
margin: 0;
}
@include e(core) {
margin: 0;
display: inline-block;
position: relative;
width: $--switch-width;
height: $--switch-height;
border: 1px solid $--switch-off-color;
outline: none;
border-radius: $--switch-core-border-radius;
box-sizing: border-box;
background: $--switch-off-color;
cursor: pointer;
transition: border-color .3s, background-color .3s;
vertical-align: middle;
&:after {
content: "";
position: absolute;
top: 1px;
left: 1px;
border-radius: $--border-radius-circle;
transition: all .3s;
width: $--switch-button-size;
height: $--switch-button-size;
background-color: $--color-white;
}
}
@include when(checked) {
.el-switch__core {
border-color: $--switch-on-color;
background-color: $--switch-on-color;
&::after {
left: 100%;
margin-left: -$--switch-button-size - 1px;
}
}
}
@include when(disabled) {
opacity: 0.6;
}
@include m(wide) {
.el-switch__label {
&.el-switch__label--left {
span {
left: 10px;
}
}
&.el-switch__label--right {
span {
right: 10px;
}
}
}
}
& .label-fade-enter,
& .label-fade-leave-active {
opacity: 0;
}
}

View File

@ -1,6 +1,6 @@
@import "./base.scss";
@import "./pagination.scss";
@import "./dialog.scss";
@import "dialog";
@import "./autocomplete.scss";
@import "./dropdown.scss";
@import "./dropdown-menu.scss";
@ -38,7 +38,7 @@
@import "./tag.scss";
@import "./tree.scss";
@import "./alert.scss";
@import "./notification.scss";
@import "notification";
@import "./slider.scss";
@import "./loading.scss";
@import "./row.scss";

View File

@ -0,0 +1,5 @@
import { render } from 'omi'
import './assets/index.css'
import './elements/switch'
render(<my-app />, '#root')

View File

@ -40,7 +40,7 @@ define('my-app', class extends WeElement {
static observe = true
data = { tag: 'my-home' }
install() {
route('/', () => {
@ -63,6 +63,16 @@ define('my-app', class extends WeElement {
route('*', function () {
console.log('not found')
})
route.before = (evt) => {
console.log('before')
//prevent route when return false
//return false
}
route.after = (evt) => {
console.log('after')
}
}
onClick = () => {

View File

@ -39,7 +39,7 @@ define('my-app', class extends WeElement {
static observe = true
data = { tag: 'my-home' }
install() {
route('/', () => {
@ -62,6 +62,16 @@ define('my-app', class extends WeElement {
route('*', function () {
console.log('not found')
})
route.before = (evt) => {
console.log('before')
//prevent route when return false
//return false
}
route.after = (evt) => {
console.log('after')
}
}
onClick = () => {

View File

@ -77,7 +77,7 @@ Object.defineProperty(exports, "__esModule", {
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/**
* omi v4.0.18 http://omijs.org
* omi v4.0.19 http://omijs.org
* Omi === Preact + Scoped CSS + Store System + Native Support in 3kb javascript.
* By dntzhang https://github.com/dntzhang
* Github: https://github.com/Tencent/omi
@ -1113,7 +1113,7 @@ var WeElement = function (_HTMLElement) {
var _this = _possibleConstructorReturn(this, _HTMLElement.call(this));
_this.props = nProps(_this.constructor.props);
_this.props = Object.assign(nProps(_this.constructor.props), _this.constructor.defaultProps);
_this.data = _this.constructor.data || {};
return _this;
}
@ -1491,9 +1491,12 @@ function getHost(ele) {
}
}
var Component = WeElement;
var omi = {
tag: tag,
WeElement: WeElement,
Component: Component,
render: render,
h: h,
createElement: h,
@ -1505,11 +1508,12 @@ var omi = {
};
options.root.Omi = omi;
options.root.Omi.version = '4.0.18';
options.root.Omi.version = '4.0.19';
exports.default = omi;
exports.tag = tag;
exports.WeElement = WeElement;
exports.Component = Component;
exports.render = render;
exports.h = h;
exports.createElement = h;
@ -1624,6 +1628,16 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
route('*', function () {
console.log('not found');
});
route.before = function (evt) {
console.log('before');
//prevent route when return false
//return false
};
route.after = function (evt) {
console.log('after');
};
}
}, {
key: 'css',
@ -1706,7 +1720,7 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
exports.default = route;
/*!
* omi-router v2.0.2 by dntzhang
* omi-router v2.0.3 by dntzhang
* Router for Omi.
* Github: https://github.com/Tencent/omi
* MIT Licensed.
@ -1729,7 +1743,12 @@ root.route.to = function (path) {
window.addEventListener('hashchange', change);
function change() {
function change(evt) {
var prevent = false;
if (evt.type === 'hashchange' && root.route.before) {
prevent = root.route.before(evt) === false;
}
if (prevent) return;
var path = window.location.hash.replace('#', '');
var notFound = true;
Object.keys(mapping).every(function (key) {
@ -1747,6 +1766,10 @@ function change() {
if (notFound) {
mapping['*'] && mapping['*'].callback();
}
if (evt.type === 'hashchange' && root.route.after) {
root.route.after(evt);
}
}
document.addEventListener('DOMContentLoaded', change);

View File

@ -31,6 +31,16 @@ define('my-app', class extends WeElement {
route('*', function () {
console.log('not found')
})
route.before = (evt) => {
console.log('before')
//prevent route when return false
//return false
}
route.after = (evt) => {
console.log('after')
}
}
onClick = () => {

View File

@ -1,5 +1,5 @@
/*!
* omi-router v2.0.2 by dntzhang
* omi-router v2.0.3 by dntzhang
* Router for Omi.
* Github: https://github.com/Tencent/omi
* MIT Licensed.
@ -22,7 +22,12 @@ root.route.to = function (path) {
window.addEventListener('hashchange', change)
function change() {
function change(evt) {
let prevent = false
if (evt.type === 'hashchange' && root.route.before) {
prevent = root.route.before(evt) === false
}
if (prevent) return
const path = window.location.hash.replace('#', '')
let notFound = true
Object.keys(mapping).every(key => {
@ -40,6 +45,10 @@ function change() {
if (notFound) {
mapping['*'] && mapping['*'].callback()
}
if (evt.type === 'hashchange' && root.route.after) {
root.route.after(evt)
}
}
document.addEventListener('DOMContentLoaded', change)

View File

@ -1,6 +1,6 @@
{
"name": "omi-router",
"version": "2.0.2",
"version": "2.0.3",
"description": "Router for Omi.",
"main": "index.js",
"scripts": {

View File

@ -40,20 +40,6 @@ class MyApp extends WeElement {
}
}
css() {
return `
div{
color: red;
cursor: pointer;
width:150px;
height:150px;
line-height:150px;
text-align: center;
border: 1px solid green;
}`;
}
installed() {
setInterval(() => {
//slow

View File

@ -1 +1,2 @@
test/ts/
examples/*/b.js

View File

@ -1,5 +1,5 @@
/**
* omi v4.0.19 http://omijs.org
* omi v4.0.20 http://omijs.org
* Omi === Preact + Scoped CSS + Store System + Native Support in 3kb javascript.
* By dntzhang https://github.com/dntzhang
* Github: https://github.com/Tencent/omi
@ -454,7 +454,9 @@
}
// otherwise, if there are existing or new children, diff them:
else if (vchildren && vchildren.length || fc != null) {
innerDiffNode(out, vchildren, context, mountAll, hydrating || props.dangerouslySetInnerHTML != null);
if (!(out.constructor.is == 'WeElement' && out.constructor.noSlot)) {
innerDiffNode(out, vchildren, context, mountAll, hydrating || props.dangerouslySetInnerHTML != null);
}
}
// Apply attributes/props from VNode to the DOM Element:
@ -1044,7 +1046,18 @@
}
this.install();
var shadowRoot = this.attachShadow({ mode: 'open' });
var shadowRoot;
if (!this.shadowRoot) {
shadowRoot = this.attachShadow({
mode: 'open'
});
} else {
shadowRoot = this.shadowRoot;
var fc;
while (fc = shadowRoot.firstChild) {
shadowRoot.removeChild(fc);
}
}
this.css && shadowRoot.appendChild(cssToDom(this.css()));
this.beforeRender();
@ -1409,7 +1422,7 @@
};
options.root.Omi = omi;
options.root.Omi.version = '4.0.19';
options.root.Omi.version = '4.0.20';
if (typeof module != 'undefined') module.exports = omi;else self.Omi = omi;
}());

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
/**
* omi v4.0.19 http://omijs.org
* omi v4.0.20 http://omijs.org
* Omi === Preact + Scoped CSS + Store System + Native Support in 3kb javascript.
* By dntzhang https://github.com/dntzhang
* Github: https://github.com/Tencent/omi
@ -451,7 +451,9 @@ function idiff(dom, vnode, context, mountAll, componentRoot) {
}
// otherwise, if there are existing or new children, diff them:
else if (vchildren && vchildren.length || fc != null) {
innerDiffNode(out, vchildren, context, mountAll, hydrating || props.dangerouslySetInnerHTML != null);
if (!(out.constructor.is == 'WeElement' && out.constructor.noSlot)) {
innerDiffNode(out, vchildren, context, mountAll, hydrating || props.dangerouslySetInnerHTML != null);
}
}
// Apply attributes/props from VNode to the DOM Element:
@ -1041,7 +1043,18 @@ var WeElement = function (_HTMLElement) {
}
this.install();
var shadowRoot = this.attachShadow({ mode: 'open' });
var shadowRoot;
if (!this.shadowRoot) {
shadowRoot = this.attachShadow({
mode: 'open'
});
} else {
shadowRoot = this.shadowRoot;
var fc;
while (fc = shadowRoot.firstChild) {
shadowRoot.removeChild(fc);
}
}
this.css && shadowRoot.appendChild(cssToDom(this.css()));
this.beforeRender();
@ -1406,7 +1419,7 @@ var omi = {
};
options.root.Omi = omi;
options.root.Omi.version = '4.0.19';
options.root.Omi.version = '4.0.20';
export default omi;
export { tag, WeElement, Component, render, h, h as createElement, options, define, observe, cloneElement, getHost };

File diff suppressed because one or more lines are too long

View File

@ -163,7 +163,7 @@
}
if (!hydrating && vchildren && 1 === vchildren.length && 'string' == typeof vchildren[0] && null != fc && void 0 !== fc.splitText && null == fc.nextSibling) {
if (fc.nodeValue != vchildren[0]) fc.nodeValue = vchildren[0];
} else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML);
} else if (vchildren && vchildren.length || null != fc) if ('WeElement' != out.constructor.is || !out.constructor.noSlot) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML);
diffAttributes(out, vnode.attributes, props);
if (out.props) out.props.children = vnode.children;
isSvgMode = prevSvgMode;
@ -723,9 +723,14 @@
if (this.store) this.store.instances.push(this);
}
this.install();
var shadowRoot = this.attachShadow({
var shadowRoot;
if (!this.shadowRoot) shadowRoot = this.attachShadow({
mode: 'open'
});
}); else {
shadowRoot = this.shadowRoot;
var fc;
while (fc = shadowRoot.firstChild) shadowRoot.removeChild(fc);
}
this.css && shadowRoot.appendChild(cssToDom(this.css()));
this.beforeRender();
options.afterInstall && options.afterInstall(this);
@ -779,7 +784,7 @@
getHost: getHost
};
options.root.Omi = omi;
options.root.Omi.version = '4.0.19';
options.root.Omi.version = '4.0.20';
if ('undefined' != typeof module) module.exports = omi; else self.Omi = omi;
}();
//# sourceMappingURL=omi.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,28 +1,21 @@
import { render, define, WeElement } from '../../src/omi'
define('my-p',
class extends WeElement {
define('my-p', class extends WeElement {
render(props) {
return props.children
}
})
render(props) {
return props.children
}
})
define('my-app', class extends WeElement {
render() {
return (
<div>
<my-p>
<h2>Hello World</h2>
</my-p>
</div>
)
}
})
define('my-app',
class extends WeElement {
render() {
return (
<div>
<my-p>
<h2>Hello World</h2>
</my-p>
</div>
)
}
})
render(
<my-app />,
'body'
)
render(<my-app />, 'body')

View File

@ -1,29 +1,28 @@
import { render, WeElement, define, observe } from '../../src/omi'
define('my-counter',
@observe
class extends WeElement {
data = {
count: 1
}
define('my-counter', @observe
class extends WeElement {
data = {
count: 1
}
sub = () => {
this.data.count--
}
sub = () => {
this.data.count--
}
add = () => {
this.data.count++
}
add = () => {
this.data.count++
}
render() {
return (
<div>
<button onClick={this.sub}>-</button>
<span>{this.data.count}</span>
<button onClick={this.add}>+</button>
</div>
)
}
})
render() {
return (
<div>
<button onClick={this.sub}>-</button>
<span>{this.data.count}</span>
<button onClick={this.add}>+</button>
</div>
)
}
})
render(<my-counter />, 'body')

View File

@ -39,21 +39,21 @@ class TodoApp extends WeElement {
)
}
handleChange = e => {
this.data.text = e.target.value
}
handleChange = e => {
this.data.text = e.target.value
}
handleSubmit = e => {
e.preventDefault()
if (!this.data.text.trim().length) {
return
}
this.data.items.push({
text: this.data.text,
id: Date.now()
})
this.data.text = ''
}
handleSubmit = e => {
e.preventDefault()
if (!this.data.text.trim().length) {
return
}
this.data.items.push({
text: this.data.text,
id: Date.now()
})
this.data.text = ''
}
}
render(<todo-app />, 'body')

View File

@ -21,24 +21,24 @@ import { options } from '../../src/omi'
* @see https://developers.google.com/web/updates/2015/08/using-requestidlecallback
*/
window.requestIdleCallback =
window.requestIdleCallback ||
function(cb) {
return setTimeout(() => {
let start = Date.now()
cb({
didTimeout: false,
timeRemaining() {
return Math.max(0, 50 - (Date.now() - start))
}
})
}, 1)
}
window.requestIdleCallback ||
function(cb) {
return setTimeout(() => {
let start = Date.now()
cb({
didTimeout: false,
timeRemaining() {
return Math.max(0, 50 - (Date.now() - start))
}
})
}, 1)
}
window.cancelIdleCallback =
window.cancelIdleCallback ||
function(id) {
clearTimeout(id)
}
window.cancelIdleCallback ||
function(id) {
clearTimeout(id)
}
options.afterInstall = function(ele) {
if (ele.constructor.observe) {

View File

@ -4,7 +4,7 @@ import { tag, render, WeElement } from '../../src/omi'
class HelloElement extends WeElement {
render(props) {
const { count } = props
return [<div>Hello</div>, <div>Element</div>,<div>{count}</div>]
return [<div>Hello</div>, <div>Element</div>, <div>{count}</div>]
}
}

View File

@ -1,11 +1,11 @@
import { define, WeElement } from '../../src/omi'
define('hello-element', class extends WeElement {
static defaultProps = {
msg: '',
propFromParent:'123111',
testDefault: 'abc'
}
static defaultProps = {
msg: '',
propFromParent: '123111',
testDefault: 'abc'
}
onClick = evt => {
// trigger CustomEvent
@ -26,7 +26,7 @@ define('hello-element', class extends WeElement {
<div onClick={this.onClick}>
Hello {props.msg} {props.propFromParent}
<div>Click Me!</div>
<div>{props.testDefault}</div>
<div>{props.testDefault}</div>
</div>
)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,29 +1,38 @@
import { tag, render, WeElement } from '../../src/omi'
import { define, render, WeElement } from '../../src/omi'
define('fancy-tabs', class extends WeElement {
static noSlot = true
@tag('hello-element')
class HelloElement extends WeElement {
render() {
return (
<div onClick={this.onClick}>
<p>
<slot name="my-text">My default text</slot>
</p>
</div>
)
return [
<div id="tabs">
<slot id="tabsSlot" name="title" />
</div>,
<div id="panels">
<slot id="panelsSlot" />
</div>,
<div>Show me only when noSlot is true!</div>
]
}
}
})
@tag('my-app')
class MyApp extends WeElement {
define('my-app', class extends WeElement {
render() {
return (
<div>
<hello-element>
<span slot="my-text">Let's have some different text!</span>
</hello-element>
<fancy-tabs>
<button slot="title">Title</button>
<button slot="title" selected>
Title 2
</button>
<button slot="title">Title 3</button>
<section>content panel 1</section>
<section>content panel 2</section>
<section>content panel 3</section>
</fancy-tabs>
</div>
)
}
}
})
render(<my-app />, 'body')

View File

@ -38,40 +38,40 @@ class TodoApp extends WeElement {
)
}
handleChange = e => {
this.store.data.text = e.target.value
}
handleChange = e => {
this.store.data.text = e.target.value
}
handleSubmit = e => {
e.preventDefault()
this.store.add()
}
handleSubmit = e => {
e.preventDefault()
this.store.add()
}
installed() {
setTimeout(() => {
this.store.rename()
}, 2000)
installed() {
setTimeout(() => {
this.store.rename()
}, 2000)
setTimeout(() => {
this.store.data.items.push({ text: 'abc' })
}, 4000)
setTimeout(() => {
this.store.data.items.push({ text: 'abc' })
}, 4000)
setTimeout(() => {
this.store.data.items[2].text = 'changed'
}, 6000)
setTimeout(() => {
this.store.data.items[2].text = 'changed'
}, 6000)
setTimeout(() => {
this.store.data.items.splice(1, 1)
}, 8000)
setTimeout(() => {
this.store.data.items.splice(1, 1)
}, 8000)
setTimeout(() => {
this.store.data.showList = false
}, 10000)
setTimeout(() => {
this.store.data.showList = false
}, 10000)
setTimeout(() => {
this.store.data.showList = true
}, 12000)
}
setTimeout(() => {
this.store.data.showList = true
}, 12000)
}
}
const store = {

View File

@ -3,12 +3,12 @@ import 'omi-tap'
@tag('my-app')
class MyApp extends WeElement {
onTap = () => {
console.log('tap')
}
onTap = () => {
console.log('tap')
}
css() {
return `
css() {
return `
div{
width: 100px;
height: 100px;
@ -18,15 +18,15 @@ class MyApp extends WeElement {
margin: 0 auto;
line-height: 93px;
}`
}
}
render() {
return (
<omi-tap onTap={this.onTap}>
<div>Tap Me!</div>
</omi-tap>
)
}
render() {
return (
<omi-tap onTap={this.onTap}>
<div>Tap Me!</div>
</omi-tap>
)
}
}
render(<my-app />, 'body')

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,16 @@
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<meta charset="UTF-8" />
<title>Add Omi in 30 Seconds</title>
</head>
<body>
<script src="b.js"></script>
<a href="https://github.com/Tencent/omi" target="_blank" style="position: fixed; right: 0; top: 0; z-index: 3;">
<img src="//alloyteam.github.io/github.png" alt="">
</a>
</body>
</html>

View File

@ -0,0 +1,27 @@
import { render, WeElement, define } from '../../src/omi'
define('my-timer', class extends WeElement {
static observe = true
data = {
seconds: 0
}
tick() {
this.data.seconds++
}
install() {
this.interval = setInterval(() => this.tick(), 1000)
}
uninstall() {
clearInterval(this.interval)
}
render() {
return <div>Seconds: {this.data.seconds}</div>
}
})
render(<my-timer />, 'body')

View File

@ -1,6 +1,6 @@
{
"name": "omi",
"version": "4.0.19",
"version": "4.0.20",
"description": "Next generation web framework.",
"main": "dist/omi.js",
"jsnext:main": "dist/omi.esm.js",
@ -19,6 +19,7 @@
"todo-app": "rollup -c config/rollup.example.js --watch",
"observe": "rollup -c config/rollup.example.js --watch",
"children": "rollup -c config/rollup.example.js --watch",
"timer": "rollup -c config/rollup.example.js --watch",
"store": "rollup -c config/rollup.example.js --watch",
"pure": "rollup -c config/rollup.example.js --watch",
"counter": "rollup -c config/rollup.example.js --watch",

View File

@ -25,7 +25,7 @@ const omi = {
}
options.root.Omi = omi
options.root.Omi.version = '4.0.19'
options.root.Omi.version = '4.0.20'
export default omi

View File

@ -161,13 +161,15 @@ function idiff(dom, vnode, context, mountAll, componentRoot) {
}
// otherwise, if there are existing or new children, diff them:
else if ((vchildren && vchildren.length) || fc != null) {
innerDiffNode(
out,
vchildren,
context,
mountAll,
hydrating || props.dangerouslySetInnerHTML != null
)
if (!(out.constructor.is == 'WeElement' && out.constructor.noSlot)) {
innerDiffNode(
out,
vchildren,
context,
mountAll,
hydrating || props.dangerouslySetInnerHTML != null
)
}
}
// Apply attributes/props from VNode to the DOM Element:

View File

@ -28,15 +28,15 @@ export default class WeElement extends HTMLElement {
}
this.install()
var shadowRoot
let shadowRoot
if (!this.shadowRoot) {
shadowRoot = this.attachShadow({
mode: 'open'
})
} else {
shadowRoot = this.shadowRoot
var fc
while (fc = shadowRoot.firstChild) {
let fc
while ((fc = shadowRoot.firstChild)) {
shadowRoot.removeChild(fc)
}
}

View File

@ -1,2 +0,0 @@
## 腾讯 Omi 生态计划

View File

@ -0,0 +1,162 @@
## 写在前面
[Omi 框架](https://github.com/Tencent/omi/) 正式发布了 [→ omi-transform](https://github.com/Tencent/omi/tree/master/packages/omi-transform)。
> Made css3 transform super easy.
![](https://github.com/Tencent/omi/raw/master/packages/omi-transform/css3transform/asset/transform.gif)
作为 Omi 组件化开发特效运动解决方案让你轻松在Omi项目里快速简便支持CSS3 Transform设置。先说说 css3transformcss3transform 作为移动 Web 特效解决方案在微信、手Q兴趣部落、日迹、QQ群、QQ附近等项目中广泛使用以激进的**修改**DOM属性为代价带来极为便利的可编程性。
你可以通过[css3transform 官方首页](https://tencent.github.io/omi/packages/omi-transform/css3transform/)快速了解它。
上面官网的例子都是原生 js 的css3transform 也拥有react版本你也可以在 react 中以声明式的方式使用 css3transform
``` js
render() {
return (
<Transform
translateX={100}
scaleX={0.5}
originX={0.5}>
<div>你要运动的 DOM</div>
</Transform>
);
}
```
这都不是重点,重点是 omi-transform。
## 3分钟掌握 omi-transform
### 通过npm安装
``` js
npm install omi-transform
```
### 使用
```js
import { render, WeElement, define } from "omi"
import "omi-transform"
define("my-app", class extends WeElement {
install() {
this.data.rotateZ = 30
this.linkRef = (e) => {
this.animDiv = e
}
}
installed() {
setInterval(() => {
//slow
// this.data.rotateZ += 2
// this.update()
//fast
this.animDiv.rotateZ += 2
//sync for update call of any scenario
this.data.rotateZ = this.animDiv.rotateZ
}, 16)
}
render(props, data) {
return (
<css3-transform rotateZ={data.rotateZ} translateX={0} perspective={0} >
<div ref={this.linkRef}>
omi-transform
</div>
</css3-transform>
)
}
})
render(<my-app />, "body")
```
* 在需要使用 css3transform 的DOM上标记 `ref` 用来直接操作 DOM
* 在组件函数里便可以使用 this.refs.xxx 来读取或者设置 css transform属性
* this.refs.xxx 支持 "translateX", "translateY", "translateZ", "scaleX", "scaleY", "scaleZ", "rotateX", "rotateY", "rotateZ", "skewX", "skewY", "originX", "originY", "originZ", "perspective" 这些属性设置和读取
* 没有标记 perspective 的话默认不使用透视投影
组件里的某个DOM在运动过程中可能会由于其他逻辑进行update。有可能是用户交互有可能是数据返回的回调。所以update前后DOM的状态的保留显得尤其重要不然的话就会有闪烁、跳跃的效果或者其他显示逻辑错误。
可以看到上面的代码在 DOM 运动过程中时不进行 Diff ?意思就是组件不进行 update
意思就是万一组件update所有运动的状态都会丢失Omi怎么解决这个问题
> 使用 `this.data.rotateZ` 来同步运动 DOM 的状态防止意外的刷新(`update`)
[→ 演示](https://tencent.github.io/omi/packages/omi/examples/css3transform/)
## 支持的属性
| **Property** | **Describe** |
| --------- | ---------------------- |
| translateX |translateX |
| translateY |translateY |
| translateZ |translateZ |
| scaleX |scaleX |
| scaleY |scaleY |
| scaleZ |scaleZ|
| rotateX |rotateX |
| rotateY |rotateY |
| rotateZ |rotateZ |
| skewX | skewX|
| skewY |skewY |
| originX | the basic x point of rotation|
| originY | the basic y point of rotation |
| originZ | the basic z point of rotation|
| perspective |Perspective projection distance |
你既可以 get 也可以 set。
## 性能对比
因为 react 版本会有 diff 过程,然后 apply diff to dom 的过程state 改变不会整个 innerHTML 全部替换,所以对浏览器渲染来说还是很便宜,但是在 js 里 diff 的过程的耗时还是需要去 profiles 一把,如果耗时严重,不在 webworker 里跑还是会卡住UI线程导致卡顿交互延缓等。所以要看一看 CPU 的耗时还是很有必要的。
下面数据是对比 omi-transform 和 react-transform两种方式使用 chrome profiles 了一把。
**先看总耗时对比**
react-transform
![](https://user-gold-cdn.xitu.io/2017/4/5/d1c804dc8700f0561f9d81fcb635576f)
omi-transform
![](https://user-gold-cdn.xitu.io/2017/4/5/19b25f47561d69b0f48ac330146cf4b4)
- react 在8739秒内CPU耗时花费了近似**1686ms**
- Omi 方式在9254ms秒内CPU耗时花费近似**700ms**
在不进行 profiles 就能想象到 react 是一定会更慢一些,因为 state 的改变要走把 react 生命周期走一遍,但是可以看到 react 的耗时还是在可以接受的范围,没有慢到难以接受。
而 Omi 的方式则和传统的原生 js 的耗时一模一样。以为运动过程不进行DOM Diff!!
## Omi 自身对比
```js
//slow
this.data.rotateZ += 2
this.update()
```
```js
//fast
this.animDiv.rotateZ += 2
this.data.rotateZ = this.animDiv.rotateZ
```
主要对比上面两个代码块的执行效率,直接看对比结果:
| **Slow** | **Fast** |
| ------------------------------- | ----------------------------------- |
| ![Omi](../assets/css3transform-update.jpg) | ![React](../assets/css3transform.jpg) |
可以看到 omi 的两种方式都拥有很高性能10秒钟内拥有大量的空闲时间但是 fast 确实更加 fastscripting 的耗时更短。但是优势不明显是为什么?因为 DOM 结构简单,如果 DOM 结构越复杂, fast 直接操作 DOM 的方式会把 slow 的方式甩开一大截!
## Star & Fork
[→ omi-transform](https://github.com/Tencent/omi/tree/master/packages/omi-transform)