Skip to content

Commit

Permalink
feat: 1st cmt
Browse files Browse the repository at this point in the history
  • Loading branch information
Simbachen committed Jul 3, 2018
1 parent eff856f commit 067e292
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 471 deletions.
86 changes: 12 additions & 74 deletions packages/taro-weapp/src/component.js
@@ -1,18 +1,16 @@
import { isEmptyObject } from './util'
import { enqueueRender } from './render-queue'
import { updateComponent } from './lifecycle'

class Component {
static defaultProps = {}
$components = {}
$$components = {}
$router = {
params: {}
}
$path = ''
$name = ''
$isComponent = true
$props = {}
// #组件state对应小程序组件data
// #私有的__componentProps更新用于触发子组件中对应obsever,生命周期componentWillReciveProps,componentShouldUpdate在这里处理
// #父组件传过来的props放到data.__props中供模板使用,这么做的目的是模拟reciveProps生命周期
// 执行顺序:组件setState -> 组件_createData() -> 对应的小程序组件setData(组件更新)-> 子组件的__componentProps.observer执行
// -> 触发子组件componentWillReciveProps,更新子组件props,componentShouldUpdate -> 子组件_createData -> 子组件setData

class BaseComponent {
// _createData的时候生成,小程序中通过data.__createData访问
__computed = {}
// this.props,小程序中通过data.__props访问
__props = {}
nextProps = {}
_dirty = true
_disable = true
Expand All @@ -23,62 +21,9 @@ class Component {
this.state = {}
this.props = props || {}
}

_initData ($root, $parent) {
this.$app = getApp()
this.$root = $root || null
this.$parent = $parent || null
this.defaultData = {}
this.$data = $parent ? $parent.$data || {} : {}

let path = this.$path.split('$$').pop()
this.$data[`$$${path}`] = this.$data[`$$${path}`] || {}
this.$data = this.$data[`$$${path}`]
let state = this.state
if (this._dyState) {
state = Object.assign({}, this.state, this._dyState)
}
for (let k in state) {
this.$data[k] = state[k]
}
if (this.props) {
for (let k in this.props) {
if (typeof this.props[k] !== 'function') {
this.$data[k] = this.props[k]
}
}
}

if (this.$$components && !isEmptyObject(this.$$components)) {
Object.getOwnPropertyNames(this.$$components).forEach(name => {
this.$$components[name]._initData(this.$root || this, this)
})
}
if (this.$$dynamicComponents && !isEmptyObject(this.$$dynamicComponents)) {
Object.getOwnPropertyNames(this.$$dynamicComponents).forEach(name => {
this.$$dynamicComponents[name]._initData(this.$root || this, this)
})
}
}
_init (scope) {
this.$scope = scope
this.$app = getApp()
if (this.$$components && !isEmptyObject(this.$$components)) {
Object.getOwnPropertyNames(this.$$components).forEach(name => {
this.$$components[name]._init(this.$scope)
})
}
if (this.$$dynamicComponents && !isEmptyObject(this.$$dynamicComponents)) {
Object.getOwnPropertyNames(this.$$dynamicComponents).forEach(name => {
this.$$dynamicComponents[name]._init(this.$scope)
})
}
}
// rewrite when compile
_createData () {
return this.state
}

setState (state, callback) {
if (state) {
(this._pendingStates = this._pendingStates || []).push(state)
Expand Down Expand Up @@ -108,13 +53,6 @@ class Component {
})
return stateClone
}

forceUpdate (callback) {
if (typeof callback === 'function') {
(this._pendingCallbacks = this._pendingCallbacks || []).push(callback)
}
updateComponent(this, true)
}
}

export default Component
export default BaseComponent
157 changes: 157 additions & 0 deletions packages/taro-weapp/src/create-component.js
@@ -0,0 +1,157 @@
import { isEmptyObject, getPrototypeChain } from './util'
import { updateComponent } from './lifecycle'
const eventPreffix = '__event_'

const privatePropValName = '__triggerObserer'

function bindProperties (weappComponentConf, ComponentClass) {
weappComponentConf.properties = ComponentClass.properties || {}
// 拦截props的更新,插入生命周期
// 调用小程序setData或会造成性能消耗
weappComponentConf.properties[privatePropValName] = {
type: null,
observer: function (newState) {
if (!this.$component.__isAttached) return
const nextProps = filterProps(ComponentClass.properties, ComponentClass.defaultProps, this.data)
this.$component.props = nextProps
updateComponent(this.$component, true, 'observer')
}
}
}

function processEvent (eventHandlerName, component, obj) {
if (eventHandlerName.indexOf(eventHandlerName) === -1) return
let originEventHandlerName = eventHandlerName.replace(eventPreffix, '')
if (obj[originEventHandlerName]) return

obj[originEventHandlerName] = function (event) {
if (event) {
event.preventDefault = function () {}
event.stopPropagation = function () {}
Object.assign(event.target, event.detail)
Object.assign(event.currentTarget, event.detail)
}
const dataset = event.currentTarget.dataset

let scope = this.$component
const bindArgs = {}
const componentClassName = dataset['componentClass']
const originEventHandlerNameLower = originEventHandlerName.toLocaleLowerCase()
Object.keys(dataset).forEach(key => {
let keyLower = key.toLocaleLowerCase()
if (keyLower.indexOf('event') === 0) {
keyLower = keyLower.replace('event', '')
keyLower = componentClassName ? `${componentClassName}__${keyLower}` : keyLower
keyLower = keyLower.toLocaleLowerCase()
if (keyLower.indexOf(originEventHandlerNameLower) >= 0) {
const argName = keyLower.replace(originEventHandlerNameLower, '')
bindArgs[argName] = dataset[key]
}
}
})
if (!isEmptyObject(bindArgs)) {
if (bindArgs['scope'] !== 'this') {
scope = bindArgs['scope']
}
delete bindArgs['scope']
const realArgs = Object.keys(bindArgs)
.sort()
.map(key => bindArgs[key])

realArgs.push(event)
component[eventHandlerName].apply(scope, realArgs)
} else {
component[eventHandlerName].call(scope, event)
}
}
}

function bindEvents (weappComponentConf, taroComponent) {
weappComponentConf.methods = weappComponentConf.methods || {}

Object.getOwnPropertyNames(taroComponent).forEach(name => {
processEvent(name, taroComponent, weappComponentConf.methods)
})

const prototypeChain = getPrototypeChain(taroComponent)
prototypeChain.forEach(item => {
Object.getOwnPropertyNames(item).forEach(name => {
processEvent(name, taroComponent, weappComponentConf.methods)
})
})
}

function filterProps (properties, defaultProps = {}, weappComponentData) {
let res = {}
Object.getOwnPropertyNames(properties).forEach(name => {
if (name !== privatePropValName) {
res[name] = name in weappComponentData ? weappComponentData[name] : defaultProps[name]
}
})
return res
}

function componentTrigger (component, key) {
if (key === 'componentWillUnmount') {
component._dirty = true
component._disable = true
}
component[key] && typeof component[key] === 'function' && component[key]()
if (key === 'componentWillMount') {
component._dirty = false
component._disable = false
}
}

function createComponent (ComponentClass, isPage) {
const component = new ComponentClass()
const weappComponentConf = {
data: {
_componentProps: 1
},

attached () {
this.$component = new ComponentClass()
this.$component._init(this)
// attached之后才可以setData,
// attached之前,小程序组件初始化时仍然会触发observer,__isAttached为否的时候放弃处理observer
this.$component.__isAttached = true
// 此处待定
componentTrigger(this.$component, 'componentWillMount')
},
ready () {
const props = filterProps(ComponentClass.properties, ComponentClass.defaultProps, this.data)
this.$component._constructor && this.$component._constructor(props)
this.$component.props = props
// 页面Ready的时候setData更新,并通过observer触发子组件更新
// 小程序组件ready,但是数据并没有ready,需要通过updateComponent来初始化数据,setData完成之后才是真正意义上的组件ready
if (this.$component.__isPage) {
updateComponent(this.$component, true, 'attached', this.$component.__isPage)
}
// 此处待定
componentTrigger(this.$component, 'componentDidMount')
},
detached () {
componentTrigger(this.$component, 'componentWillUnmount')
},
onHide () {
componentTrigger(this.$component, 'componentDidHide')
}
}
if (isPage) {
weappComponentConf['onLoad'] = weappComponentConf['attached']
weappComponentConf['onReady'] = weappComponentConf['ready']
weappComponentConf['onUnload'] = weappComponentConf['detached']
weappComponentConf['onShow'] = function () {
componentTrigger(this.$component, 'componentDidShow')
}
weappComponentConf['onHide'] = function () {
componentTrigger(this.$component, 'componentDidHide')
}
}
bindProperties(weappComponentConf, ComponentClass)
bindEvents(weappComponentConf, component)
return weappComponentConf
}

export default createComponent

0 comments on commit 067e292

Please sign in to comment.