* [jsfm] use ES6 class in vdom
Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/25b0101d Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/25b0101d Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/25b0101d Branch: refs/heads/0.16-dev Commit: 25b0101dff7635932718d8d5feee2ad9e9a2f1dc Parents: 66804f2 Author: Hanks <zhanghan...@gmail.com> Authored: Mon Aug 7 15:27:33 2017 +0800 Committer: Hanks <zhanghan...@gmail.com> Committed: Mon Aug 7 15:27:33 2017 +0800 ---------------------------------------------------------------------- html5/runtime/listener.js | 83 ++++++++++---------- html5/runtime/vdom/comment.js | 40 +++++----- html5/runtime/vdom/document.js | 126 +++++++++++++++---------------- html5/runtime/vdom/element-types.js | 17 +---- html5/runtime/vdom/element.js | 90 +++++++++++----------- html5/runtime/vdom/node.js | 47 ++++++------ 6 files changed, 183 insertions(+), 220 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/25b0101d/html5/runtime/listener.js ---------------------------------------------------------------------- diff --git a/html5/runtime/listener.js b/html5/runtime/listener.js index 4b5b270..2bf3893 100644 --- a/html5/runtime/listener.js +++ b/html5/runtime/listener.js @@ -18,40 +18,33 @@ */ /** - * @fileOverview - * Listen virtual-dom operations and create corresponding actions. - */ - -import '../shared/objectAssign' - -export default function Listener (id, handler) { - this.id = id - this.batched = false - this.updates = [] - if (typeof handler === 'function') { - Object.defineProperty(this, 'handler', { - configurable: true, - enumerable: true, - writable: true, - value: handler - }) - } - else { - console.error('[JS Runtime] invalid parameter, handler must be a function') - } -} - -/** - * Create the action object. - * @param {string} name - * @param {array} arguments - * @return {object} action - */ -export function createAction (name, args = []) { +* Create the action object. +* @param {string} name +* @param {array} arguments +* @return {object} action +*/ +function createAction (name, args = []) { return { module: 'dom', method: name, args: args } } -Object.assign(Listener.prototype, { +export default class Listener { + constructor (id, handler) { + this.id = id + this.batched = false + this.updates = [] + if (typeof handler === 'function') { + Object.defineProperty(this, 'handler', { + configurable: true, + enumerable: true, + writable: true, + value: handler + }) + } + else { + console.error('[JS Runtime] invalid parameter, handler must be a function') + } + } + /** * Send the "createFinish" signal. * @param {function} callback @@ -60,7 +53,7 @@ Object.assign(Listener.prototype, { createFinish (callback) { const handler = this.handler return handler([createAction('createFinish')], callback) - }, + } /** * Send the "updateFinish" signal. @@ -70,7 +63,7 @@ Object.assign(Listener.prototype, { updateFinish (callback) { const handler = this.handler return handler([createAction('updateFinish')], callback) - }, + } /** * Send the "refreshFinish" signal. @@ -80,7 +73,7 @@ Object.assign(Listener.prototype, { refreshFinish (callback) { const handler = this.handler return handler([createAction('refreshFinish')], callback) - }, + } /** * Send the "createBody" signal. @@ -98,7 +91,7 @@ Object.assign(Listener.prototype, { })) } return this.addActions(actions) - }, + } /** * Send the "addElement" signal. @@ -112,7 +105,7 @@ Object.assign(Listener.prototype, { index = -1 } return this.addActions(createAction('addElement', [ref, element.toJSON(), index])) - }, + } /** * Send the "removeElement" signal. @@ -125,7 +118,7 @@ Object.assign(Listener.prototype, { return this.addActions(actions) } return this.addActions(createAction('removeElement', [ref])) - }, + } /** * Send the "moveElement" signal. @@ -136,7 +129,7 @@ Object.assign(Listener.prototype, { */ moveElement (targetRef, parentRef, index) { return this.addActions(createAction('moveElement', [targetRef, parentRef, index])) - }, + } /** * Send the "updateAttrs" signal. @@ -149,7 +142,7 @@ Object.assign(Listener.prototype, { const result = {} result[key] = value return this.addActions(createAction('updateAttrs', [ref, result])) - }, + } /** * Send the "updateStyle" signal, update a sole style. @@ -162,7 +155,7 @@ Object.assign(Listener.prototype, { const result = {} result[key] = value return this.addActions(createAction('updateStyle', [ref, result])) - }, + } /** * Send the "updateStyle" signal. @@ -172,7 +165,7 @@ Object.assign(Listener.prototype, { */ setStyles (ref, style) { return this.addActions(createAction('updateStyle', [ref, style])) - }, + } /** * Send the "addEvent" signal. @@ -182,7 +175,7 @@ Object.assign(Listener.prototype, { */ addEvent (ref, type) { return this.addActions(createAction('addEvent', [ref, type])) - }, + } /** * Send the "removeEvent" signal. @@ -192,7 +185,7 @@ Object.assign(Listener.prototype, { */ removeEvent (ref, type) { return this.addActions(createAction('removeEvent', [ref, type])) - }, + } /** * Default handler. @@ -202,7 +195,7 @@ Object.assign(Listener.prototype, { */ handler (actions, cb) { return cb && cb() - }, + } /** * Add actions into updates. @@ -224,4 +217,4 @@ Object.assign(Listener.prototype, { return handler(actions) } } -}) +} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/25b0101d/html5/runtime/vdom/comment.js ---------------------------------------------------------------------- diff --git a/html5/runtime/vdom/comment.js b/html5/runtime/vdom/comment.js index 687b4cb..24d3482 100644 --- a/html5/runtime/vdom/comment.js +++ b/html5/runtime/vdom/comment.js @@ -17,31 +17,27 @@ * under the License. */ -/** - * @fileOverview - * Virtual-DOM Comment. - */ - import Node from './node' import { uniqueId } from './operation' -export default function Comment (value) { - this.nodeType = 8 - this.nodeId = uniqueId() - this.ref = this.nodeId - this.type = 'comment' - this.value = value - this.children = [] - this.pureChildren = [] -} +export default class Comment extends Node { + constructor (value) { + super() -Comment.prototype = Object.create(Node.prototype) -Comment.prototype.constructor = Comment + this.nodeType = 8 + this.nodeId = uniqueId() + this.ref = this.nodeId + this.type = 'comment' + this.value = value + this.children = [] + this.pureChildren = [] + } -/** - * Convert to HTML comment string. - * @return {stirng} html - */ -Comment.prototype.toString = function () { - return '<!-- ' + this.value + ' -->' + /** + * Convert to HTML comment string. + * @return {stirng} html + */ + toString () { + return '<!-- ' + this.value + ' -->' + } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/25b0101d/html5/runtime/vdom/document.js ---------------------------------------------------------------------- diff --git a/html5/runtime/vdom/document.js b/html5/runtime/vdom/document.js index ef8ef4e..64b6210 100644 --- a/html5/runtime/vdom/document.js +++ b/html5/runtime/vdom/document.js @@ -17,12 +17,6 @@ * under the License. */ -/** - * @fileOverview - * Virtual-DOM Document. - */ - -import '../../shared/objectAssign' import Comment from './comment' import Element from './element' import Listener from '../listener' @@ -30,22 +24,6 @@ import { TaskCenter } from '../task-center' import { createHandler } from '../handler' import { addDoc, removeDoc, appendBody, setBody } from './operation' -export default function Document (id, url, handler) { - id = id ? id.toString() : '' - this.id = id - this.URL = url - - addDoc(id, this) - this.nodeMap = {} - const L = Document.Listener || Listener - this.listener = new L(id, handler || createHandler(id, Document.handler)) // deprecated - this.taskCenter = new TaskCenter(id, handler ? (id, ...args) => handler(...args) : Document.handler) - this.createDocumentElement() -} - -// default task handler -Document.handler = null - /** * Update all changes for an element. * @param {object} element @@ -62,34 +40,47 @@ function updateElement (el, changes) { } } -Object.assign(Document.prototype, { +export default class Document { + constructor (id, url, handler) { + id = id ? id.toString() : '' + this.id = id + this.URL = url + + addDoc(id, this) + this.nodeMap = {} + const L = Document.Listener || Listener + this.listener = new L(id, handler || createHandler(id, Document.handler)) // deprecated + this.taskCenter = new TaskCenter(id, handler ? (id, ...args) => handler(...args) : Document.handler) + this.createDocumentElement() + } + /** - * Get the node from nodeMap. - * @param {string} reference id - * @return {object} node - */ + * Get the node from nodeMap. + * @param {string} reference id + * @return {object} node + */ getRef (ref) { return this.nodeMap[ref] - }, + } /** - * Turn on batched updates. - */ + * Turn on batched updates. + */ open () { this.listener.batched = false - }, + } /** - * Turn off batched updates. - */ + * Turn off batched updates. + */ close () { this.listener.batched = true - }, + } /** - * Create the document element. - * @return {object} documentElement - */ + * Create the document element. + * @return {object} documentElement + */ createDocumentElement () { if (!this.documentElement) { const el = new Element('document') @@ -121,14 +112,14 @@ Object.assign(Document.prototype, { } return this.documentElement - }, + } /** - * Create the body element. - * @param {string} type - * @param {objct} props - * @return {object} body element - */ + * Create the body element. + * @param {string} type + * @param {objct} props + * @return {object} body element + */ createBody (type, props) { if (!this.body) { const el = new Element(type, props) @@ -136,35 +127,35 @@ Object.assign(Document.prototype, { } return this.body - }, + } /** - * Create an element. - * @param {string} tagName - * @param {objct} props - * @return {object} element - */ + * Create an element. + * @param {string} tagName + * @param {objct} props + * @return {object} element + */ createElement (tagName, props) { return new Element(tagName, props) - }, + } /** - * Create an comment. - * @param {string} text - * @return {object} comment - */ + * Create an comment. + * @param {string} text + * @return {object} comment + */ createComment (text) { return new Comment(text) - }, + } /** - * Fire an event on specified element manually. - * @param {object} element - * @param {string} event type - * @param {object} event object - * @param {object} dom changes - * @return {} anything returned by handler function - */ + * Fire an event on specified element manually. + * @param {object} element + * @param {string} event type + * @param {object} event object + * @param {object} dom changes + * @return {} anything returned by handler function + */ fireEvent (el, type, e, domChanges) { if (!el) { return @@ -179,11 +170,11 @@ Object.assign(Document.prototype, { } const isBubble = this.getRef('_root').attr['bubble'] === 'true' return el.fireEvent(type, e, isBubble) - }, + } /** - * Destroy current document, and remove itself form docMap. - */ + * Destroy current document, and remove itself form docMap. + */ destroy () { this.taskCenter.destroyCallback() delete this.listener @@ -191,4 +182,7 @@ Object.assign(Document.prototype, { delete this.taskCenter removeDoc(this.id) } -}) +} + +// default task handler +Document.handler = null http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/25b0101d/html5/runtime/vdom/element-types.js ---------------------------------------------------------------------- diff --git a/html5/runtime/vdom/element-types.js b/html5/runtime/vdom/element-types.js index 369fc2d..4eb6bae 100644 --- a/html5/runtime/vdom/element-types.js +++ b/html5/runtime/vdom/element-types.js @@ -42,22 +42,11 @@ export function registerElement (type, methods) { } // Init constructor. - const XElement = function (props) { - Element.call(this, type, props, true) - } - - // Init prototype. - XElement.prototype = Object.create(Element.prototype) - Object.defineProperty(XElement.prototype, 'constructor', { - configurable: false, - enumerable: false, - writable: false, - value: Element - }) + class WeexElement extends Element {} // Add methods to prototype. methods.forEach(methodName => { - XElement.prototype[methodName] = function (...args) { + WeexElement.prototype[methodName] = function (...args) { const taskCenter = getTaskCenter(this.docId) if (taskCenter) { return taskCenter.send('component', { @@ -70,7 +59,7 @@ export function registerElement (type, methods) { }) // Add to element type map. - elementTypes[type] = XElement + elementTypes[type] = WeexElement } /** http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/25b0101d/html5/runtime/vdom/element.js ---------------------------------------------------------------------- diff --git a/html5/runtime/vdom/element.js b/html5/runtime/vdom/element.js index 3d725b9..5f5268c 100644 --- a/html5/runtime/vdom/element.js +++ b/html5/runtime/vdom/element.js @@ -17,12 +17,6 @@ * under the License. */ -/** - * @fileOverview - * Virtual-DOM Element. - */ - -import '../../shared/objectAssign' import Node from './node' import { getDoc, @@ -35,44 +29,42 @@ import { moveIndex, removeIndex } from './operation' -import { - elementTypes, - setElement -} from './element-types' +import { elementTypes, setElement } from './element-types' import { filterDirective } from './directive' const DEFAULT_TAG_NAME = 'div' -const BUBBLE_EVENTS = ['click', 'longpress', 'touchstart', 'touchmove', 'touchend', 'panstart', 'panmove', 'panend', 'horizontalpan', 'verticalpan', 'swipe'] - -export default function Element (type = DEFAULT_TAG_NAME, props, isExtended) { - const XElement = elementTypes[type] - if (XElement && !isExtended) { - return new XElement(props) - } - props = props || {} - this.nodeType = 1 - this.nodeId = uniqueId() - this.ref = this.nodeId - this.type = type - this.attr = props.attr || {} - this.style = props.style || {} - this.classStyle = props.classStyle || {} - this.event = {} - this.children = [] - this.pureChildren = [] -} - -Element.prototype = Object.create(Node.prototype) -Element.prototype.constructor = Element +const BUBBLE_EVENTS = [ + 'click', 'longpress', 'touchstart', 'touchmove', 'touchend', + 'panstart', 'panmove', 'panend', 'horizontalpan', 'verticalpan', 'swipe' +] function registerNode (docId, node) { const doc = getDoc(docId) doc.nodeMap[node.nodeId] = node } -setElement(Element) +export default class Element extends Node { + constructor (type = DEFAULT_TAG_NAME, props, isExtended) { + super() + + const WeexElement = elementTypes[type] + if (WeexElement && !isExtended) { + return new WeexElement(props) + } + + props = props || {} + this.nodeType = 1 + this.nodeId = uniqueId() + this.ref = this.nodeId + this.type = type + this.attr = props.attr || {} + this.style = props.style || {} + this.classStyle = props.classStyle || {} + this.event = {} + this.children = [] + this.pureChildren = [] + } -Object.assign(Element.prototype, { /** * Append a child node. * @param {object} node @@ -115,7 +107,7 @@ Object.assign(Element.prototype, { } } } - }, + } /** * Insert a node before specified node. @@ -177,7 +169,7 @@ Object.assign(Element.prototype, { } } } - }, + } /** * Insert a node after specified node. @@ -234,7 +226,7 @@ Object.assign(Element.prototype, { } } } - }, + } /** * Remove a child node, and decide whether it should be destroyed. @@ -259,7 +251,7 @@ Object.assign(Element.prototype, { if (!preserved) { node.destroy() } - }, + } /** * Clear all child nodes. @@ -281,7 +273,7 @@ Object.assign(Element.prototype, { }) this.children.length = 0 this.pureChildren.length = 0 - }, + } /** * Set an attribute, and decide whether the task should be send to native. @@ -304,7 +296,7 @@ Object.assign(Element.prototype, { [this.ref, result] ) } - }, + } /** * Set a style property, and decide whether the task should be send to native. @@ -327,7 +319,7 @@ Object.assign(Element.prototype, { [this.ref, result] ) } - }, + } /** * Set style properties from class. @@ -348,7 +340,7 @@ Object.assign(Element.prototype, { [this.ref, this.toStyle()] ) } - }, + } /** * Add an event handler. @@ -367,7 +359,7 @@ Object.assign(Element.prototype, { ) } } - }, + } /** * Remove an event handler. @@ -385,7 +377,7 @@ Object.assign(Element.prototype, { ) } } - }, + } /** * Fire an event manually. @@ -415,7 +407,7 @@ Object.assign(Element.prototype, { } return result - }, + } /** * Get all styles of current element. @@ -423,7 +415,7 @@ Object.assign(Element.prototype, { */ toStyle () { return Object.assign({}, this.classStyle, this.style) - }, + } /** * Convert current element to JSON like object. @@ -444,7 +436,7 @@ Object.assign(Element.prototype, { result.children = this.pureChildren.map((child) => child.toJSON()) } return result - }, + } /** * Convert to HTML element tag string. @@ -457,4 +449,6 @@ Object.assign(Element.prototype, { this.pureChildren.map((child) => child.toString()).join('') + '</' + this.type + '>' } -}) +} + +setElement(Element) http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/25b0101d/html5/runtime/vdom/node.js ---------------------------------------------------------------------- diff --git a/html5/runtime/vdom/node.js b/html5/runtime/vdom/node.js index 559d210..f36d0a5 100644 --- a/html5/runtime/vdom/node.js +++ b/html5/runtime/vdom/node.js @@ -17,33 +17,30 @@ * under the License. */ -/** - * @fileOverview - * Virtual-DOM Node. It's the supper class of Element and Comment. - */ - import { getDoc, uniqueId } from './operation' -export default function Node () { - this.nodeId = uniqueId() - this.ref = this.nodeId - this.children = [] - this.pureChildren = [] - this.parentNode = null - this.nextSibling = null - this.previousSibling = null -} +export default class Node { + constructor () { + this.nodeId = uniqueId() + this.ref = this.nodeId + this.children = [] + this.pureChildren = [] + this.parentNode = null + this.nextSibling = null + this.previousSibling = null + } -/** - * Destroy current node, and remove itself form nodeMap. - */ -Node.prototype.destroy = function () { - const doc = getDoc(this.docId) - if (doc) { - delete this.docId - delete doc.nodeMap[this.nodeId] + /** + * Destroy current node, and remove itself form nodeMap. + */ + destroy () { + const doc = getDoc(this.docId) + if (doc) { + delete this.docId + delete doc.nodeMap[this.nodeId] + } + this.children.forEach(child => { + child.destroy() + }) } - this.children.forEach(child => { - child.destroy() - }) }