fix: sync omix 2.4.0 #531

This commit is contained in:
dntzhang 2020-02-18 10:37:35 +08:00
parent 8238ff9296
commit b57e0546b0
4 changed files with 489 additions and 301 deletions

View File

@ -8,6 +8,9 @@ create(store, {
return this.a.name.split('').reverse().join('')
}
},
data: {
value: "内部数据"
},
onLoad: function () {
setTimeout(_ => {
store.a.changeName()

View File

@ -1,5 +1,6 @@
<view>
<text>{{a.name}}</text>
<text>{{b.name}}-{{b.age}}</text>
<text>{{$.a.name}}</text>
<text>{{$.b.name}}-{{$.b.age}}</text>
<view >{{reverseName}}</view>
<view>{{value}}</view>
</view>

View File

@ -1,5 +1,5 @@
/*!
* omix v2.1.0 by dntzhang
* omix v2.4.0 by dntzhang
* Github: https://github.com/Tencent/omi
* MIT Licensed.
*/
@ -7,55 +7,182 @@
import obaa from './obaa'
import { getPath, needUpdate, fixPath, getUsing } from './path'
const changes = []
function create(store, option) {
if (arguments.length === 2) {
if (!store.instances) {
store.instances = {}
}
if(!store.onChange){
store.onChange = function(fn){
if (!store.__changes_) {
store.__changes_ = []
}
const changes = store.__changes_
if (!store.onChange) {
store.onChange = function (fn) {
changes.push(fn)
}
}
if(!store.offChange){
store.offChange = function(fn){
for(let i = 0,len =changes.length;i<len;i++){
if(changes[i] === fn){
if (!store.offChange) {
store.offChange = function (fn) {
for (let i = 0, len = changes.length; i < len; i++) {
if (changes[i] === fn) {
changes.splice(i, 1)
break
}
}
}
}
option.data = store.data
const hasData = typeof option.data !== 'undefined'
let clone
if (option.data) {
clone = JSON.parse(JSON.stringify(option.data))
option.data.$ = store.data
} else {
option.data = store.data
}
observeStore(store)
const onLoad = option.onLoad
const onUnload = option.onUnload
option.onLoad = function (e) {
this.store = store
option.use && (this.__updatePath = getPath(option.use))
this.__use = option.use
store.instances[this.route] = []
this.__hasData = hasData
if (hasData) {
Object.assign(option.data, JSON.parse(JSON.stringify(clone)))
}
store.instances[this.route] = store.instances[this.route] || []
store.instances[this.route].push(this)
this.computed = option.computed
this.setData(option.data)
const using = getUsing(store.data, option.use)
option.computed && compute(option.computed, store, using)
option.computed && compute(option.computed, store, using, this)
this.setData(using)
onLoad && onLoad.call(this, e)
}
option.onUnload = function (e) {
store.instances[this.route] = store.instances[this.route].filter(ins => ins !== this)
onUnload && onUnload.call(this, e)
}
Page(option)
} else {
const ready = (store.lifetimes && store.lifetimes.ready) || store.ready
store.lifetimes = store.lifetimes || {}
const ready = store.lifetimes.ready || store.ready
store.ready = store.lifetimes.ready = function () {
const page = getCurrentPages()[getCurrentPages().length - 1]
store.use && (this.__updatePath = getPath(store.use))
this.store = page.store
this.__use = store.use
this.computed = store.computed
store.data = this.store.data
this.setData(store.data)
const using = getUsing(this.store.data, store.use)
store.computed && compute(store.computed, this.store, using, this)
this.setData(using)
page._omixComponents = page._omixComponents || []
page._omixComponents.push(this)
ready && ready.call(this)
}
Component(store)
}
}
create.Page = function (store, option) {
create(store, option)
}
create.Component = function (store, option) {
if (arguments.length === 2) {
if (!store.instances) {
store.instances = {}
}
if (!store.__changes_) {
store.__changes_ = []
}
const changes = store.__changes_
if (!store.onChange) {
store.onChange = function (fn) {
changes.push(fn)
}
}
if (!store.offChange) {
store.offChange = function (fn) {
for (let i = 0, len = changes.length; i < len; i++) {
if (changes[i] === fn) {
changes.splice(i, 1)
break
}
}
}
}
const hasData = typeof option.data !== 'undefined'
let clone
if (option.data) {
clone = JSON.parse(JSON.stringify(option.data))
option.data.$ = store.data
} else {
option.data = store.data
}
observeStore(store)
const detached = option.detached
option.lifetimes = option.lifetimes || {}
const created = option.lifetimes.created || option.created
const ready = option.lifetimes.ready || option.ready
option.created = option.lifetimes.created = function (e) {
this.store = store
option.use && (this.__updatePath = getPath(option.use))
this.__use = option.use
this.__hasData = hasData
if (hasData) {
Object.assign(option.data, JSON.parse(JSON.stringify(clone)))
}
created && created.call(this, e)
}
option.ready = option.lifetimes.ready = function (e) {
const store = this.store
store.instances[this.route] = store.instances[this.route] || []
store.instances[this.route].push(this)
this.computed = option.computed
this.setData(option.data)
const using = getUsing(store.data, option.use)
option.computed && compute(option.computed, store, using, this)
this.setData(using)
ready && ready.call(this, e)
}
option.lifetimes.detached = option.detached = function (e) {
this.store.instances[this.route] = this.store.instances[this.route].filter(ins => ins !== this)
detached && detached.call(this, e)
}
Component(option)
} else {
store.lifetimes = store.lifetimes || {}
const ready = store.lifetimes.ready || store.ready
store.ready = store.lifetimes.ready = function () {
const page = getCurrentPages()[getCurrentPages().length - 1]
store.use && (this.__updatePath = getPath(store.use))
@ -66,77 +193,135 @@ function create(store, option) {
this.setData(store.data)
const using = getUsing(this.store.data, store.use)
store.computed && compute(store.computed, this.store, using)
store.computed && compute(store.computed, this.store, using, this)
this.setData(using)
this.store.instances[page.route].push(this)
page._omixComponents = page._omixComponents || []
page._omixComponents.push(this)
ready && ready.call(this)
}
Component(store)
}
}
function compute(computed, store, using){
for(let key in computed){
using[key] = computed[key].call(store.data)
function compute(computed, store, using, scope) {
for (let key in computed) {
using[key] = computed[key].call(store.data, scope)
}
}
function observeStore(store) {
obaa(store.data, (prop, value, old, path) => {
const oba = obaa(store.data, (prop, value, old, path) => {
let patch = {}
if (prop.indexOf('Array-push') === 0) {
let dl = value.length - old.length
for (let i = 0; i < dl; i++) {
patch[ fixPath(path + '-' + (old.length + i))] = value[(old.length + i)]
patch[fixPath(path + '-' + (old.length + i))] = value[(old.length + i)]
}
} else if (prop.indexOf('Array-') === 0) {
patch[ fixPath(path)] = value
patch[fixPath(path)] = value
} else {
patch[ fixPath(path + '-' + prop)] = value
patch[fixPath(path + '-' + prop)] = value
}
_update(patch, store)
})
if (!store.set) {
store.set = function (obj, prop, val) {
obaa.set(obj, prop, val, oba)
}
}
const backer = store.data
Object.defineProperty(store, 'data', {
enumerable: true,
get: function() {
return backer
},
set: function() {
throw new Error('You must not replace store.data directly, instead assign nest prop')
}
})
}
function _update(kv, store) {
for (let key in store.instances) {
store.instances[key].forEach(ins => {
if(store.updateAll || ins.__updatePath && needUpdate(kv,ins.__updatePath)){
ins.setData.call(ins, kv)
const using = getUsing(store.data, ins.__use)
compute(ins.computed, store, using)
ins.setData(using)
_updateOne(kv, store, ins)
if(ins._omixComponents){
ins._omixComponents.forEach(compIns => {
_updateOne(kv, store, compIns)
})
}
})
}
changes.forEach(change => {
store.__changes_.forEach(change => {
change(kv)
})
store.debug && storeChangeLogger(store, kv)
}
function storeChangeLogger (store, diffResult) {
try {
const preState = wx.getStorageSync(`CurrentState`) || {}
const title = `State Changed`
console.groupCollapsed(`%c ${ title } %c ${ Object.keys(diffResult) }`, 'color:#e0c184; font-weight: bold', 'color:#f0a139; font-weight: bold')
console.log(`%c Pre State`, 'color:#ff65af; font-weight: bold', preState)
console.log(`%c Change State`, 'color:#3d91cf; font-weight: bold', diffResult)
console.log(`%c Next State`, 'color:#2c9f67; font-weight: bold', store.data)
console.groupEnd()
wx.setStorageSync(`CurrentState`, store.data)
} catch (e) {
console.log(e)
function _updateOne(kv, store, ins){
if (!(store.updateAll || ins.__updatePath && needUpdate(kv, ins.__updatePath))) {
return
}
if (!ins.__hasData) {
return _updateImpl(kv, store, ins)
}
const patch = Object.assign({}, kv)
for (let pk in patch) {
if (!/\$\./.test(pk)) {
patch['$.' + pk] = kv[pk]
delete patch[pk]
}
}
_updateImpl(patch, store, ins)
}
function _updateImpl(data, store, ins) {
if (!wx.nextTick) {
return _doUpdate(data, store, ins)
}
if (ins._omixDataBuffer === undefined) {
ins._omixDataBuffer = {}
}
Object.assign(ins._omixDataBuffer, data)
if (!ins._omixTickScheduled) {
wx.nextTick(function() {
_doUpdate(ins._omixDataBuffer, store, ins)
ins._omixDataBuffer = {}
ins._omixTickScheduled = false
})
ins._omixTickScheduled = true
}
}
function _doUpdate(data, store, ins) {
if (Object.keys(data).length === 0) {
return
}
ins.setData.call(ins, data)
const using = getUsing(store.data, ins.__use)
ins.computed && compute(ins.computed, store, using, ins)
ins.setData.call(ins, using)
}
function storeChangeLogger(store, diffResult) {
try {
const preState = wx.getStorageSync(`CurrentState`) || {}
const title = `Data Changed`
console.groupCollapsed(`%c ${title} %c ${Object.keys(diffResult)}`, 'color:#e0c184; font-weight: bold', 'color:#f0a139; font-weight: bold')
console.log(`%c Pre Data`, 'color:#ff65af; font-weight: bold', preState)
console.log(`%c Change Data`, 'color:#3d91cf; font-weight: bold', diffResult)
console.log(`%c Next Data`, 'color:#2c9f67; font-weight: bold', store.data)
console.groupEnd()
wx.setStorageSync(`CurrentState`, store.data)
} catch (e) {
console.log(e)
}
}

View File

@ -3,285 +3,284 @@
* Github: https://github.com/Tencent/omi
* MIT Licensed.
*/
;(function(win) {
var obaa = function(target, arr, callback) {
var _observe = function(target, arr, callback) {
//if (!target.$observer) target.$observer = this
var $observer = this
var eventPropArr = []
if (obaa.isArray(target)) {
if (target.length === 0) {
Object.defineProperty(target, '$observeProps', {
configurable: true,
enumerable: false,
writable: true,
value: {}
})
target.$observeProps.$observerPath = '#'
}
$observer.mock(target)
export default function obaa(target, arr, callback) {
var _observe = function (target, arr, callback) {
//if (!target.$observer) target.$observer = this
var $observer = this
var eventPropArr = []
if (obaa.isArray(target)) {
if (target.length === 0) {
$observer.track(target)
}
for (var prop in target) {
if (target.hasOwnProperty(prop)) {
if (callback) {
if (obaa.isArray(arr) && obaa.isInArray(arr, prop)) {
eventPropArr.push(prop)
$observer.watch(target, prop)
} else if (obaa.isString(arr) && prop == arr) {
eventPropArr.push(prop)
$observer.watch(target, prop)
}
} else {
$observer.mock(target)
}
if (target && typeof target === 'object' && Object.keys(target).length === 0) {
$observer.track(target)
}
for (var prop in target) {
if (target.hasOwnProperty(prop)) {
if (callback) {
if (obaa.isArray(arr) && obaa.isInArray(arr, prop)) {
eventPropArr.push(prop)
$observer.watch(target, prop)
} else if (obaa.isString(arr) && prop == arr) {
eventPropArr.push(prop)
$observer.watch(target, prop)
}
} else {
eventPropArr.push(prop)
$observer.watch(target, prop)
}
}
$observer.target = target
if (!$observer.propertyChangedHandler)
$observer.propertyChangedHandler = []
var propChanged = callback ? callback : arr
$observer.propertyChangedHandler.push({
all: !callback,
propChanged: propChanged,
eventPropArr: eventPropArr
})
}
_observe.prototype = {
onPropertyChanged: function(prop, value, oldValue, target, path) {
if (value !== oldValue && (!(nan(value) && nan(oldValue))) && this.propertyChangedHandler) {
var rootName = obaa._getRootName(prop, path)
for (
var i = 0, len = this.propertyChangedHandler.length;
i < len;
i++
$observer.target = target
if (!$observer.propertyChangedHandler)
$observer.propertyChangedHandler = []
var propChanged = callback ? callback : arr
$observer.propertyChangedHandler.push({
all: !callback,
propChanged: propChanged,
eventPropArr: eventPropArr
})
}
_observe.prototype = {
onPropertyChanged: function (prop, value, oldValue, target, path) {
if (value !== oldValue && (!(nan(value) && nan(oldValue))) && this.propertyChangedHandler) {
var rootName = obaa._getRootName(prop, path)
for (
var i = 0, len = this.propertyChangedHandler.length;
i < len;
i++
) {
var handler = this.propertyChangedHandler[i]
if (
handler.all ||
obaa.isInArray(handler.eventPropArr, rootName) ||
rootName.indexOf('Array-') === 0
) {
var handler = this.propertyChangedHandler[i]
if (
handler.all ||
obaa.isInArray(handler.eventPropArr, rootName) ||
rootName.indexOf('Array-') === 0
) {
handler.propChanged.call(this.target, prop, value, oldValue, path)
}
handler.propChanged.call(this.target, prop, value, oldValue, path)
}
}
if (prop.indexOf('Array-') !== 0 && typeof value === 'object') {
this.watch(target, prop, target.$observeProps.$observerPath)
}
},
mock: function(target) {
var self = this
obaa.methods.forEach(function(item) {
target[item] = function() {
var old = Array.prototype.slice.call(this, 0)
var result = Array.prototype[item].apply(
this,
Array.prototype.slice.call(arguments)
)
if (new RegExp('\\b' + item + '\\b').test(obaa.triggerStr)) {
for (var cprop in this) {
if (
this.hasOwnProperty(cprop) &&
!obaa.isFunction(this[cprop])
) {
self.watch(this, cprop, this.$observeProps.$observerPath)
}
}
if (prop.indexOf('Array-') !== 0 && typeof value === 'object') {
this.watch(target, prop, target.$observeProps.$observerPath)
}
},
mock: function (target) {
var self = this
obaa.methods.forEach(function (item) {
target[item] = function () {
var old = Array.prototype.slice.call(this, 0)
var result = Array.prototype[item].apply(
this,
Array.prototype.slice.call(arguments)
)
if (new RegExp('\\b' + item + '\\b').test(obaa.triggerStr)) {
for (var cprop in this) {
if (
this.hasOwnProperty(cprop) &&
!obaa.isFunction(this[cprop])
) {
self.watch(this, cprop, this.$observeProps.$observerPath)
}
//todo
self.onPropertyChanged(
'Array-' + item,
this,
old,
this,
this.$observeProps.$observerPath
)
}
return result
}
target[
'pure' + item.substring(0, 1).toUpperCase() + item.substring(1)
] = function() {
return Array.prototype[item].apply(
this,
Array.prototype.slice.call(arguments)
)
}
})
},
watch: function(target, prop, path) {
if (prop === '$observeProps' || prop === '$observer') return
if (obaa.isFunction(target[prop])) return
if (!target.$observeProps){
Object.defineProperty(target, '$observeProps', {
configurable: true,
enumerable: false,
writable: true,
value: {}
})
}
if (path !== undefined) {
target.$observeProps.$observerPath = path
} else {
target.$observeProps.$observerPath = '#'
}
var self = this
var currentValue = (target.$observeProps[prop] = target[prop])
Object.defineProperty(target, prop, {
get: function() {
return this.$observeProps[prop]
},
set: function(value) {
var old = this.$observeProps[prop]
this.$observeProps[prop] = value
//todo
self.onPropertyChanged(
prop,
value,
'Array-' + item,
this,
old,
this,
target.$observeProps.$observerPath
this.$observeProps.$observerPath
)
}
return result
}
target[
'pure' + item.substring(0, 1).toUpperCase() + item.substring(1)
] = function () {
return Array.prototype[item].apply(
this,
Array.prototype.slice.call(arguments)
)
}
})
},
watch: function (target, prop, path) {
if (prop === '$observeProps' || prop === '$observer') return
if (obaa.isFunction(target[prop])) return
if (!target.$observeProps) {
Object.defineProperty(target, '$observeProps', {
configurable: true,
enumerable: false,
writable: true,
value: {}
})
if (typeof currentValue == 'object') {
if (obaa.isArray(currentValue)) {
this.mock(currentValue)
//为0就不会进下面的 for 循环,就不会执行里面的 watch就不会有 $observeProps 属性
if (currentValue.length === 0) {
if (!currentValue.$observeProps){
Object.defineProperty(currentValue, '$observeProps', {
configurable: true,
enumerable: false,
writable: true,
value: {}
})
}
if (path !== undefined) {
currentValue.$observeProps.$observerPath = path + '-' + prop
} else {
currentValue.$observeProps.$observerPath = '#' + '-' + prop
}
}
}
if (path !== undefined) {
target.$observeProps.$observerPath = path
} else {
target.$observeProps.$observerPath = '#'
}
var self = this
var currentValue = (target.$observeProps[prop] = target[prop])
Object.defineProperty(target, prop, {
get: function () {
return this.$observeProps[prop]
},
set: function (value) {
var old = this.$observeProps[prop]
this.$observeProps[prop] = value
self.onPropertyChanged(
prop,
value,
old,
this,
target.$observeProps.$observerPath
)
}
})
if (typeof currentValue == 'object') {
if (obaa.isArray(currentValue)) {
this.mock(currentValue)
//为0就不会进下面的 for 循环,就不会执行里面的 watch就不会有 $observeProps 属性
if (currentValue.length === 0) {
this.track(currentValue, prop, path)
}
for (var cprop in currentValue) {
if (currentValue.hasOwnProperty(cprop)) {
this.watch(
currentValue,
cprop,
target.$observeProps.$observerPath + '-' + prop
)
}
}
if (currentValue && Object.keys(currentValue).length === 0) {
this.track(currentValue, prop, path)
}
for (var cprop in currentValue) {
if (currentValue.hasOwnProperty(cprop)) {
this.watch(
currentValue,
cprop,
target.$observeProps.$observerPath + '-' + prop
)
}
}
}
}
return new _observe(target, arr, callback)
}
obaa.methods = [
'concat',
'copyWithin',
'entries',
'every',
'fill',
'filter',
'find',
'findIndex',
'forEach',
'includes',
'indexOf',
'join',
'keys',
'lastIndexOf',
'map',
'pop',
'push',
'reduce',
'reduceRight',
'reverse',
'shift',
'slice',
'some',
'sort',
'splice',
'toLocaleString',
'toString',
'unshift',
'values',
'size'
]
obaa.triggerStr = [
'concat',
'copyWithin',
'fill',
'pop',
'push',
'reverse',
'shift',
'sort',
'splice',
'unshift',
'size'
].join(',')
obaa.isArray = function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]'
}
obaa.isString = function(obj) {
return typeof obj === 'string'
}
obaa.isInArray = function(arr, item) {
for (var i = arr.length; --i > -1; ) {
if (item === arr[i]) return true
}
return false
}
obaa.isFunction = function(obj) {
return Object.prototype.toString.call(obj) == '[object Function]'
}
obaa._getRootName = function(prop, path) {
if (path === '#') {
return prop
}
return path.split('-')[1]
}
obaa.add = function(obj, prop) {
var $observer = obj.$observer
$observer.watch(obj, prop)
}
obaa.set = function(obj, prop, value, exec) {
if (!exec) {
obj[prop] = value
}
var $observer = obj.$observer
$observer.watch(obj, prop)
if (exec) {
obj[prop] = value
},
track: function(obj, prop, path) {
if (obj.$observeProps) {
return
}
Object.defineProperty(obj, '$observeProps', {
configurable: true,
enumerable: false,
writable: true,
value: {}
})
if (path !== undefined && path !== null) {
obj.$observeProps.$observerPath = path + '-' + prop
} else {
if (prop !== undefined && prop !== null) {
obj.$observeProps.$observerPath = '#' + '-' + prop
} else {
obj.$observeProps.$observerPath = '#'
}
}
}
}
return new _observe(target, arr, callback)
}
Array.prototype.size = function(length) {
this.length = length
}
obaa.methods = [
'concat',
'copyWithin',
'entries',
'every',
'fill',
'filter',
'find',
'findIndex',
'forEach',
'includes',
'indexOf',
'join',
'keys',
'lastIndexOf',
'map',
'pop',
'push',
'reduce',
'reduceRight',
'reverse',
'shift',
'slice',
'some',
'sort',
'splice',
'toLocaleString',
'toString',
'unshift',
'values',
'size'
]
obaa.triggerStr = [
'concat',
'copyWithin',
'fill',
'pop',
'push',
'reverse',
'shift',
'sort',
'splice',
'unshift',
'size'
].join(',')
function nan(value) {
return typeof value === "number" && isNaN(value)
}
obaa.isArray = function (obj) {
return Object.prototype.toString.call(obj) === '[object Array]'
}
if (
typeof module != 'undefined' &&
module.exports
) {
module.exports = obaa
} else if (typeof define === 'function' && define.amd) {
define(obaa)
} else {
win.obaa = obaa
obaa.isString = function (obj) {
return typeof obj === 'string'
}
obaa.isInArray = function (arr, item) {
for (var i = arr.length; --i > -1;) {
if (item === arr[i]) return true
}
})(Function('return this')())
return false
}
obaa.isFunction = function (obj) {
return Object.prototype.toString.call(obj) == '[object Function]'
}
obaa._getRootName = function (prop, path) {
if (path === '#') {
return prop
}
return path.split('-')[1]
}
obaa.add = function (obj, prop) {
var $observer = obj.$observer
$observer.watch(obj, prop)
}
obaa.set = function (obj, prop, value, oba) {
// if (exec) {
// obj[prop] = value
// }
if (obj[prop] === undefined) {
var $observer = obj.$observer || oba
$observer.watch(obj, prop, obj.$observeProps.$observerPath)
}
//if (!exec) {
obj[prop] = value
//}
}
Array.prototype.size = function (length) {
this.length = length
}
function nan(value) {
return typeof value === "number" && isNaN(value)
}