feat: multi-store injection supported in omio
This commit is contained in:
parent
4b0f364a62
commit
902a75f2ce
|
@ -1,7 +1,7 @@
|
|||
import WeElement from './we-element'
|
||||
import options from './options'
|
||||
|
||||
export function define(name, ctor) {
|
||||
export function define(name, ctor, config) {
|
||||
if (options.mapping[name]) {
|
||||
return
|
||||
}
|
||||
|
@ -10,24 +10,11 @@ export function define(name, ctor) {
|
|||
options.mapping[name] = ctor
|
||||
|
||||
} else {
|
||||
let depPaths
|
||||
let config = {}
|
||||
const len = arguments.length
|
||||
if (len === 3) {
|
||||
if (typeof arguments[1] === 'function') {
|
||||
ctor = arguments[1]
|
||||
config = arguments[2]
|
||||
} else {
|
||||
depPaths = arguments[1]
|
||||
ctor = arguments[2]
|
||||
}
|
||||
} else if (len === 4) {
|
||||
depPaths = arguments[1]
|
||||
ctor = arguments[2]
|
||||
config = arguments[3]
|
||||
}
|
||||
|
||||
if (typeof config === 'string') {
|
||||
config = { css: config }
|
||||
} else {
|
||||
config = config || { }
|
||||
}
|
||||
|
||||
class Ele extends WeElement {
|
||||
|
|
|
@ -162,7 +162,7 @@ declare namespace Omi {
|
|||
|
||||
function render(vnode: ComponentChild, parent: string | Element | Document | ShadowRoot | DocumentFragment, store?: object): any;
|
||||
|
||||
function define(name: string, ctorOrDepPaths: any[] | WeElementConstructor, ctorOrOptions?: WeElementConstructor | string | object, cssStringOrOptions?: string | object): void;
|
||||
function define(name: string, ctor: WeElementConstructor, cssStringOrOptions?: string | object): void;
|
||||
function defineElement(name: string, ctorOrDepPaths: any[] | WeElementConstructor, ctorOrOptions?: WeElementConstructor | string | object, cssStringOrOptions?: string | object): void;
|
||||
function tag(name: string, pure?: boolean): (ctor: WeElementConstructor) => void;
|
||||
function tick(callback: Callback, scope?: any): void;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,16 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
|
||||
<meta charset="UTF-8" />
|
||||
<title>Counter</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>
|
|
@ -0,0 +1,52 @@
|
|||
import { define, render } from '../../src/omi'
|
||||
|
||||
define('my-app', _ => {
|
||||
const store = _.store.storeA
|
||||
const { data, add, sub } = store
|
||||
return (
|
||||
<p>
|
||||
Clicked: {data.count} times
|
||||
<button onClick={add}>+</button>
|
||||
<button onClick={sub}>-</button>
|
||||
|
||||
<div>
|
||||
{_.store.storeB.data.msg}
|
||||
<button onClick={_.store.storeB.changeMsg}>
|
||||
change storeB's msg
|
||||
</button>
|
||||
</div>
|
||||
</p>
|
||||
)
|
||||
}, {
|
||||
useSelf: {
|
||||
storeA: ['count', 'adding'],
|
||||
storeB: ['msg']
|
||||
}
|
||||
})
|
||||
|
||||
const storeA = new class Store {
|
||||
data = {
|
||||
count: 0,
|
||||
adding: false
|
||||
}
|
||||
sub = () => {
|
||||
this.data.count--
|
||||
}
|
||||
add = () => {
|
||||
this.data.count++
|
||||
}
|
||||
}
|
||||
|
||||
const storeB = new class Store {
|
||||
data = {
|
||||
msg: 'abc'
|
||||
}
|
||||
changeMsg = () => {
|
||||
this.data.msg = 'bcd'
|
||||
}
|
||||
}
|
||||
|
||||
render( <my-app /> , 'body', {
|
||||
storeA,
|
||||
storeB
|
||||
})
|
|
@ -1,38 +1,19 @@
|
|||
import options from './options'
|
||||
import Component from './component'
|
||||
|
||||
const OBJECTTYPE = '[object Object]'
|
||||
const ARRAYTYPE = '[object Array]'
|
||||
|
||||
export function define(name, ctor) {
|
||||
export function define(name, ctor, config) {
|
||||
if(ctor.is === 'WeElement'){
|
||||
options.mapping[name] = ctor
|
||||
if (ctor.use) {
|
||||
ctor.updatePath = getPath(ctor.use)
|
||||
}
|
||||
} else {
|
||||
let depPaths
|
||||
let config = {}
|
||||
const len = arguments.length
|
||||
if(len === 3){
|
||||
if(typeof arguments[1] === 'function'){
|
||||
ctor = arguments[1]
|
||||
config = arguments[2]
|
||||
} else {
|
||||
depPaths = arguments[1]
|
||||
ctor = arguments[2]
|
||||
}
|
||||
} else if(len === 4){
|
||||
depPaths = arguments[1]
|
||||
ctor = arguments[2]
|
||||
config = arguments[3]
|
||||
}
|
||||
|
||||
if(typeof config === 'string'){
|
||||
config = { css: config }
|
||||
}
|
||||
} else {
|
||||
config = config || {}
|
||||
}
|
||||
|
||||
class Comp extends Component {
|
||||
static use = depPaths
|
||||
|
||||
static css = config.css
|
||||
|
||||
|
@ -104,79 +85,6 @@ export function define(name, ctor) {
|
|||
}
|
||||
}
|
||||
|
||||
if(Comp.use){
|
||||
Comp.updatePath = getPath(Comp.use)
|
||||
}
|
||||
|
||||
options.mapping[name] = Comp
|
||||
}
|
||||
}
|
||||
|
||||
export function getPath(obj) {
|
||||
if (Object.prototype.toString.call(obj) === '[object Array]') {
|
||||
const result = {}
|
||||
obj.forEach(item => {
|
||||
if (typeof item === 'string') {
|
||||
result[item] = true
|
||||
} else {
|
||||
const tempPath = item[Object.keys(item)[0]]
|
||||
if (typeof tempPath === 'string') {
|
||||
result[tempPath] = true
|
||||
} else {
|
||||
if(typeof tempPath[0] === 'string'){
|
||||
result[tempPath[0]] = true
|
||||
}else{
|
||||
tempPath[0].forEach(path => result[path] = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
} else {
|
||||
return getUpdatePath(obj)
|
||||
}
|
||||
}
|
||||
|
||||
export function getUpdatePath(data) {
|
||||
const result = {}
|
||||
dataToPath(data, result)
|
||||
return result
|
||||
}
|
||||
|
||||
function dataToPath(data, result) {
|
||||
Object.keys(data).forEach(key => {
|
||||
result[key] = true
|
||||
const type = Object.prototype.toString.call(data[key])
|
||||
if (type === OBJECTTYPE) {
|
||||
_objToPath(data[key], key, result)
|
||||
} else if (type === ARRAYTYPE) {
|
||||
_arrayToPath(data[key], key, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function _objToPath(data, path, result) {
|
||||
Object.keys(data).forEach(key => {
|
||||
result[path + '.' + key] = true
|
||||
delete result[path]
|
||||
const type = Object.prototype.toString.call(data[key])
|
||||
if (type === OBJECTTYPE) {
|
||||
_objToPath(data[key], path + '.' + key, result)
|
||||
} else if (type === ARRAYTYPE) {
|
||||
_arrayToPath(data[key], path + '.' + key, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function _arrayToPath(data, path, result) {
|
||||
data.forEach((item, index) => {
|
||||
result[path + '[' + index + ']'] = true
|
||||
delete result[path]
|
||||
const type = Object.prototype.toString.call(item)
|
||||
if (type === OBJECTTYPE) {
|
||||
_objToPath(item, path + '[' + index + ']', result)
|
||||
} else if (type === ARRAYTYPE) {
|
||||
_arrayToPath(item, path + '[' + index + ']', result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ declare namespace Omi {
|
|||
|
||||
function render(vnode: ComponentChild, parent: string | Element | Document | ShadowRoot | DocumentFragment, store?: object, empty?: boolean, merge?: string | Element | Document | ShadowRoot | DocumentFragment): void;
|
||||
|
||||
function define(name: string, ctor: WeElementConstructor): void;
|
||||
function define(name: string, ctor: WeElementConstructor, cssStringOrOptions?: string | object): void;
|
||||
function tag(name: string, pure?: boolean): (ctor: WeElementConstructor) => void;
|
||||
function tick(callback: Callback, scope?: any): void;
|
||||
function nextTick(callback: Callback, scope?: any): void;
|
||||
|
|
|
@ -31,7 +31,8 @@ export default {
|
|||
doc: typeof document === 'object' ? document : null,
|
||||
root: getGlobal(),
|
||||
//styleCache :[{ctor:ctor,ctorName:ctorName,style:style}]
|
||||
styleCache: []
|
||||
styleCache: [],
|
||||
isMultiStore: false
|
||||
//componentChange(component, element) { },
|
||||
/** If `true`, `prop` changes trigger synchronous component updates.
|
||||
* @name syncComponentUpdates
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { diff } from './vdom/diff'
|
||||
import obaa from './obaa'
|
||||
import { getUse } from './util'
|
||||
import options from './options'
|
||||
|
||||
/** Render JSX into a `parent` Element.
|
||||
* @param {VNode} vnode A (JSX) VNode to render
|
||||
|
@ -10,7 +11,18 @@ import { getUse } from './util'
|
|||
*/
|
||||
export function render(vnode, parent, store, empty, merge) {
|
||||
parent = typeof parent === 'string' ? document.querySelector(parent) : parent
|
||||
obsStore(store)
|
||||
|
||||
if(store && store.data){
|
||||
|
||||
obsStore(store)
|
||||
} else {
|
||||
options.isMultiStore = true
|
||||
for(let key in store){
|
||||
if(store[key].data){
|
||||
obsStore(store[key], key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
while (parent.firstChild) {
|
||||
|
@ -28,19 +40,18 @@ export function render(vnode, parent, store, empty, merge) {
|
|||
return diff(merge, vnode, store, false, parent, false)
|
||||
}
|
||||
|
||||
function obsStore(store){
|
||||
if (store && store.data) {
|
||||
store.instances = []
|
||||
store.updateSelfInstances = []
|
||||
extendStoreUpate(store)
|
||||
function obsStore(store, storeName){
|
||||
|
||||
store.instances = []
|
||||
store.updateSelfInstances = []
|
||||
extendStoreUpate(store, storeName)
|
||||
|
||||
obaa(store.data, (prop, val, old, path) => {
|
||||
const patchs = {}
|
||||
const key = fixPath(path + '-' + prop)
|
||||
patchs[key] = true
|
||||
store.update(patchs)
|
||||
})
|
||||
}
|
||||
obaa(store.data, (prop, val, old, path) => {
|
||||
const patchs = {}
|
||||
const key = fixPath(path + '-' + prop)
|
||||
patchs[key] = true
|
||||
store.update(patchs)
|
||||
})
|
||||
}
|
||||
|
||||
export function merge(vnode, merge, store) {
|
||||
|
@ -54,34 +65,44 @@ export function merge(vnode, merge, store) {
|
|||
return diff(merge, vnode, store)
|
||||
}
|
||||
|
||||
function extendStoreUpate(store) {
|
||||
function extendStoreUpate(store, key) {
|
||||
store.update = function(patch) {
|
||||
const updateAll = matchGlobalData(this.globalData, patch)
|
||||
if (Object.keys(patch).length > 0) {
|
||||
this.instances.forEach(instance => {
|
||||
if (
|
||||
updateAll ||
|
||||
this.updateAll ||
|
||||
(instance.constructor.updatePath &&
|
||||
needUpdate(patch, instance.constructor.updatePath)) ||
|
||||
(instance._updatePath &&
|
||||
needUpdate(patch, instance._updatePath))
|
||||
) {
|
||||
//update this.use
|
||||
if(instance.constructor.use){
|
||||
instance.using = getUse(store.data, instance.constructor.use)
|
||||
} else if(instance.use){
|
||||
instance.using = getUse(store.data, typeof instance.use === 'function' ? instance.use() : instance.use)
|
||||
}
|
||||
if (key) {
|
||||
if ((
|
||||
instance._updatePath && instance._updatePath[key] && needUpdate(patch, instance._updatePath[key]))) {
|
||||
if (instance.use) {
|
||||
getUse(store.data, (typeof instance.use === 'function' ? instance.use() : instance.use)[key], instance.using, key)
|
||||
}
|
||||
|
||||
instance.update()
|
||||
instance.update()
|
||||
}
|
||||
} else {
|
||||
if (instance._updatePath && needUpdate(patch, instance._updatePath)) {
|
||||
if(instance.use){
|
||||
instance.using = getUse(store.data, typeof instance.use === 'function' ? instance.use() : instance.use)
|
||||
}
|
||||
instance.update()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.updateSelfInstances.forEach(instance => {
|
||||
if (instance._updateSelfPath && needUpdate(patch, instance._updateSelfPath)) {
|
||||
instance.usingSelf = getUse(store.data, typeof instance.useSelf === 'function' ? instance.useSelf() : instance.useSelf)
|
||||
instance.updateSelf()
|
||||
if (key) {
|
||||
if ((
|
||||
instance._updateSelfPath && instance._updateSelfPath[key] && needUpdate(patch, instance._updateSelfPath[key]))) {
|
||||
if (instance.useSelf) {
|
||||
getUse(store.data, (typeof instance.useSelf === 'function' ? instance.useSelf() : instance.useSelf)[key], instance.usingSelf, key)
|
||||
}
|
||||
|
||||
instance.updateSelf()
|
||||
}
|
||||
} else {
|
||||
if (instance._updateSelfPath && needUpdate(patch, instance._updateSelfPath)) {
|
||||
instance.usingSelf = getUse(store.data, typeof instance.useSelf === 'function' ? instance.useSelf() : instance.useSelf)
|
||||
instance.updateSelf()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -90,20 +111,6 @@ function extendStoreUpate(store) {
|
|||
}
|
||||
}
|
||||
|
||||
export function matchGlobalData(globalData, diffResult) {
|
||||
if (!globalData) return false
|
||||
for (let keyA in diffResult) {
|
||||
if (globalData.indexOf(keyA) > -1) {
|
||||
return true
|
||||
}
|
||||
for (let i = 0, len = globalData.length; i < len; i++) {
|
||||
if (includePath(keyA, globalData[i])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function needUpdate(diffResult, updatePath) {
|
||||
for (let keyA in diffResult) {
|
||||
|
|
|
@ -186,7 +186,7 @@ export function nProps(props) {
|
|||
return result
|
||||
}
|
||||
|
||||
export function getUse(data, paths) {
|
||||
export function getUse(data, paths, out, name) {
|
||||
const obj = []
|
||||
paths.forEach((path, index) => {
|
||||
const isPath = typeof path === 'string'
|
||||
|
@ -213,6 +213,7 @@ export function getUse(data, paths) {
|
|||
obj[key] = obj[index]
|
||||
}
|
||||
})
|
||||
out && (out[name] = obj)
|
||||
return obj
|
||||
}
|
||||
|
||||
|
@ -224,3 +225,29 @@ export function getTargetByPath(origin, path) {
|
|||
}
|
||||
return current
|
||||
}
|
||||
|
||||
|
||||
export function getPath(obj, out, name) {
|
||||
|
||||
const result = {}
|
||||
obj.forEach(item => {
|
||||
if (typeof item === 'string') {
|
||||
result[item] = true
|
||||
} else {
|
||||
const tempPath = item[Object.keys(item)[0]]
|
||||
if (typeof tempPath === 'string') {
|
||||
result[tempPath] = true
|
||||
} else {
|
||||
if(typeof tempPath[0] === 'string'){
|
||||
result[tempPath[0]] = true
|
||||
}else{
|
||||
tempPath[0].forEach(path => result[path] = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
out && (out[name] = result)
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Component from '../component'
|
||||
import { getUse } from '../util'
|
||||
import { getPath } from '../define'
|
||||
import { getUse, getPath } from '../util'
|
||||
import options from '../options'
|
||||
/** Retains a pool of Components for re-use, keyed on component name.
|
||||
* Note: since component names are not unique or even necessarily available, these are primarily a form of sharding.
|
||||
* @private
|
||||
|
@ -28,22 +28,47 @@ export function createComponent(Ctor, props, context, vnode) {
|
|||
}
|
||||
vnode && (inst.scopedCssAttr = vnode.css)
|
||||
|
||||
if ( inst.store && inst.store.data) {
|
||||
if(inst.constructor.use){
|
||||
inst.using = getUse(inst.store.data, inst.constructor.use)
|
||||
inst.store.instances.push(inst)
|
||||
} else if(inst.use){
|
||||
const use = typeof inst.use === 'function' ? inst.use() : inst.use
|
||||
inst._updatePath = getPath(use)
|
||||
inst.using = getUse(inst.store.data, use)
|
||||
inst.store.instances.push(inst)
|
||||
if (inst.store) {
|
||||
if(inst.use){
|
||||
const use = typeof inst.use === 'function' ? inst.use() : inst.use
|
||||
|
||||
if(options.isMultiStore){
|
||||
let _updatePath = {}
|
||||
let using = {}
|
||||
for (let storeName in use) {
|
||||
_updatePath[storeName] = {}
|
||||
using[storeName] = {}
|
||||
getPath(use[storeName], _updatePath, storeName)
|
||||
getUse(inst.store[storeName].data, use[storeName], using, storeName)
|
||||
inst.store[storeName].instances.push(inst)
|
||||
}
|
||||
inst.using = using
|
||||
inst._updatePath = _updatePath
|
||||
}else{
|
||||
inst._updatePath = getPath(use)
|
||||
inst.using = getUse(inst.store.data, use)
|
||||
inst.store.instances.push(inst)
|
||||
}
|
||||
}
|
||||
|
||||
if(inst.useSelf){
|
||||
const use = typeof inst.useSelf === 'function' ? inst.useSelf() : inst.useSelf
|
||||
inst._updateSelfPath = getPath(use)
|
||||
inst.usingSelf = getUse(inst.store.data, use)
|
||||
inst.store.updateSelfInstances.push(inst)
|
||||
const use = typeof inst.useSelf === 'function' ? inst.useSelf() : inst.useSelf
|
||||
|
||||
if (options.isMultiStore) {
|
||||
let _updatePath = {}
|
||||
let using = {}
|
||||
for (let storeName in use) {
|
||||
getPath(use[storeName], _updatePath, storeName)
|
||||
getUse(inst.store[storeName].data, use[storeName], using, storeName)
|
||||
inst.store[storeName].updateSelfInstances.push(inst)
|
||||
}
|
||||
inst.usingSelf = using
|
||||
inst._updateSelfPath = _updatePath
|
||||
} else {
|
||||
inst._updateSelfPath = getPath(use)
|
||||
inst.usingSelf = getUse(inst.store.data, use)
|
||||
inst.store.updateSelfInstances.push(inst)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ describe('install()', () => {
|
|||
expect(scratch.innerHTML).to.equal('<div>Ele</div>')
|
||||
})
|
||||
|
||||
it('should render components', () => {
|
||||
it('should render components b', () => {
|
||||
define('my-ele', () => {
|
||||
return <div>Ele2</div>
|
||||
})
|
||||
|
@ -63,7 +63,7 @@ describe('install()', () => {
|
|||
|
||||
|
||||
|
||||
it('should render components', () => {
|
||||
it('should render components c', () => {
|
||||
define('my-ele', _ => {
|
||||
return <div>{_.props.msg}</div>
|
||||
})
|
||||
|
|
|
@ -52,7 +52,7 @@ h1{
|
|||
}
|
||||
}
|
||||
|
||||
Preact.render(<Comp />, document.querySelector('#root3'))
|
||||
Preact.render(<Comp />, document.querySelector('#root'))
|
||||
```
|
||||
|
||||
## How to use rpx unit like omi ?
|
||||
|
@ -107,7 +107,7 @@ class Comp extends Preact.Component {
|
|||
}
|
||||
}
|
||||
|
||||
Preact.render(<Comp />, document.querySelector('#root3'))
|
||||
Preact.render(<Comp />, document.querySelector('#root'))
|
||||
```
|
||||
|
||||
## Related links
|
||||
|
|
Loading…
Reference in New Issue