UNPKG

migi

Version:

A JavaScript MVVM on JSX

1,274 lines (1,201 loc) 40.7 kB
define(function(require, exports, module){'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var _Event = require('./Event'); var _Event2 = _interopRequireDefault(_Event); var _Element2 = require('./Element'); var _Element3 = _interopRequireDefault(_Element2); var _Component = require('./Component'); var _Component2 = _interopRequireDefault(_Component); var _util = require('./util'); var _util2 = _interopRequireDefault(_util); var _Obj = require('./Obj'); var _Obj2 = _interopRequireDefault(_Obj); var _Cb = require('./Cb'); var _Cb2 = _interopRequireDefault(_Cb); var _range = require('./range'); var _range2 = _interopRequireDefault(_range); var _match = require('./match'); var _match2 = _interopRequireDefault(_match); var _domDiff = require('./domDiff'); var _domDiff2 = _interopRequireDefault(_domDiff); var _type = require('./type'); var _type2 = _interopRequireDefault(_type); var _fixEvent = require('./fixEvent'); var _fixEvent2 = _interopRequireDefault(_fixEvent); var _attr = require('./attr'); var _attr2 = _interopRequireDefault(_attr); var _hash = require('./hash'); var _hash2 = _interopRequireDefault(_hash); var _touch = require('./touch'); var _touch2 = _interopRequireDefault(_touch); var _delegate = require('./delegate'); var _delegate2 = _interopRequireDefault(_delegate); var _matchUtil = require('./matchUtil'); var _matchUtil2 = _interopRequireDefault(_matchUtil); var _eventCaseName = require('./eventCaseName'); var _eventCaseName2 = _interopRequireDefault(_eventCaseName); var _selfClose = require('./selfClose'); var _selfClose2 = _interopRequireDefault(_selfClose); var _dev = require('./dev'); var _dev2 = _interopRequireDefault(_dev); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var TOUCH = { 'swipe': true, 'swipeleft': true, 'swiperight': true, 'swipeup': true, 'swipedown': true, 'longtap': true, 'doubletap': true }; function convertSelector(selector) { if (selector instanceof _Element3.default) { return selector.name + '[migi-uid="' + selector.__uid + '"]'; } return selector.replace(/(^|\s|,|])([A-Z][\w$]*)\b/, '$1[migi-name="$2"]'); } function _find(name, children) { return _findAll(name, children, true)[0] || null; } function _findAll(name, children, first) { return __findAll(name, children, [], first); } function __findAll(name, children, res, first) { for (var i = 0, len = children.length; i < len; i++) { var child = children[i]; if (child instanceof _Element3.default) { res = __findEq(name, child, res, first); } else if (child instanceof _Obj2.default) { child = child.v; if (Array.isArray(child)) { res = __findAll(name, child, res, first); } else if (child instanceof _Element3.default) { res = __findEq(name, child, res, first); } } else if (Array.isArray(child)) { res = __findAll(name, child, res, first); } if (first && res.length) { break; } } return res; } function __findEq(name, child, res, first) { // cp不递归 if (child instanceof _Component2.default) { if (child instanceof name) { res.push(child); } } // vd递归 else { if (child instanceof name) { res.push(child); if (first) { return res; } } res = res.concat(child.findAll(name, first)); } return res; } var VirtualDom = function (_Element) { _inherits(VirtualDom, _Element); function VirtualDom(uid, name, props, children) { _classCallCheck(this, VirtualDom); // 自闭合标签不能有children if (_selfClose2.default.hasOwnProperty(name) && children && children.length) { throw new Error('self-close tag can not has children: ' + name); } var _this = _possibleConstructorReturn(this, (VirtualDom.__proto__ || Object.getPrototypeOf(VirtualDom)).call(this, uid, name, props, children)); var self = _this; self.__names = null; // 从Component根节点到自己的tagName列表,以便css计算 self.__classes = null; // 同上,class列表 self.__ids = null; // 同上,id列表 // self.__hover = false; // 是否处于鼠标hover状态 // self.__active = false; // 是否处于鼠标active状态 // self.__listener = null; // 添加的event的cb引用,remove时使用 // self.__init(name, children); return _this; } // @override _createClass(VirtualDom, [{ key: 'toString', value: function toString() { var self = this; var res = '<' + self.__name; // 处理属性 for (var i = 0, len = self.__props.length; i < len; i++) { var item = self.__props[i]; var s = self.__renderProp(item[0], item[1]); res += s; } // 使用jaw内联css需解析 if (self.__style) { var s = self.__match(true); if (s) { if (res.indexOf(' style="') > 1) { res = res.replace(/ style="[^"]*"/, ' style="' + s + '"'); } else { res = res + ' style="' + s + '"'; } } } res += ' migi-uid="' + self.__uid + '"'; // :input要侦听数据绑定 self.__checkListener(); // 自闭合标签特殊处理 if (self.__selfClose) { return res + '/>'; } res += '>'; // 有dangerouslySetInnerHTML直接返回 if (self.props.dangerouslySetInnerHTML) { var s = self.props.dangerouslySetInnerHTML; if (s instanceof _Obj2.default) { s = s.toSourceString(); } else if (Array.isArray(s)) { s = _util2.default.joinSourceArray(s); } else { s = _util2.default.stringify(s); } res += s; } // 渲染children else { res += self.__renderChildren(); } res += '</' + self.__name + '>'; return res; } // @override }, { key: 'preString', value: function preString() { var self = this; // 处理属性 for (var i = 0, len = self.__props.length; i < len; i++) { var item = self.__props[i]; self.__renderProp(item[0], item[1]); } // 使用jaw内联css需解析 if (self.__style) { self.__match(true); } // :input要侦听数据绑定 self.__checkListener(); // 渲染children self.__renderChildren(); } // 始终以缓存的props属性为准,哪怕更改了真实DOM的属性 }, { key: 'isFirst', value: function isFirst(children) { // 本身就是Component的唯一节点 if (this.parent instanceof _Component2.default) { return true; } children = children || this.parent.children; for (var i = 0, len = children.length; i < len; i++) { var child = children[i]; if (Array.isArray(child) && child.length) { return this.isFirst(child); } else if (child == this) { return true; } else if (child instanceof VirtualDom) { return false; } else if (child instanceof _Obj2.default) { child = child.v; if (Array.isArray(child) && child.length) { return this.isFirst(child); } } } } }, { key: 'isLast', value: function isLast(children) { // 本身就是Component的唯一节点 if (this.parent instanceof _Component2.default) { return true; } children = children || this.parent.children; for (var i = children.length - 1; i >= 0; i--) { var child = children[i]; if (Array.isArray(child) && child.length) { return this.isLast(child); } else if (child == this) { return true; } else if (child instanceof VirtualDom) { return false; } else if (child instanceof _Obj2.default) { child = child.v; if (Array.isArray(child) && child.length) { return this.isLast(child); } } } } }, { key: 'isEmpty', value: function isEmpty() { return childEmpty(this.children); } }, { key: 'isEnabled', value: function isEnabled() { return !this.__cache.disabled; } }, { key: 'isDisabled', value: function isDisabled() { return this.__cache.disabled; } }, { key: 'isChecked', value: function isChecked() { return this.__cache.checked; } }, { key: 'prev', value: function prev() { var res = {}; getPrev(this.parent.children, this, res, function (child) { res.prev = child; }); return res.prev; } }, { key: 'prevAll', value: function prevAll(sel) { var res = { prev: [] }; getPrev(this.parent.children, this, res, function (child) { if (sel && !_matchUtil2.default.nci(sel, child) || !sel) { res.prev.push(child); } }); return res.prev; } }, { key: 'next', value: function next() { var res = {}; getNext(this.parent.children, this, res, function (child) { res.next = child; res.done = true; }); return res.next; } }, { key: 'nextAll', value: function nextAll(sel) { var res = { next: [] }; getNext(this.parent.children, this, res, function (child) { if (sel && !_matchUtil2.default.nci(sel, child) || !sel) { res.next.push(child); } }); return res.next; } }, { key: 'isOnly', value: function isOnly() { return this.siblings().length == 1; } }, { key: 'isOnlyOfType', value: function isOnlyOfType(sel) { var self = this; var all = self.siblings(); for (var i = 0, len = all.length; i < len; i++) { var item = all[i]; if (item != self && !_matchUtil2.default.nci(sel, item)) { return false; } } return true; } }, { key: 'isFirstOfType', value: function isFirstOfType(sel) { var prevAll = this.prevAll(sel); for (var i = 0, len = prevAll.length; i < len; i++) { if (!_matchUtil2.default.nci(sel, prevAll[i])) { return false; } } return true; } }, { key: 'isLastOfType', value: function isLastOfType(sel) { var nextAll = this.nextAll(sel); for (var i = 0, len = nextAll.length; i < len; i++) { if (!_matchUtil2.default.nci(sel, nextAll[i])) { return false; } } return true; } }, { key: 'siblings', value: function siblings() { var parent = this.parent; var all = allChildren(parent.children); return all; } }, { key: 'getIdx', value: function getIdx(reverse) { var siblings = this.siblings(); var i = siblings.indexOf(this); if (i > -1) { return reverse ? siblings.length - i - 1 : i; } return -1; } }, { key: 'getIdxOfType', value: function getIdxOfType(sel, reverse) { var siblings = reverse ? this.nextAll(sel) : this.prevAll(sel); if (reverse) { siblings.unshift(this); } else { siblings.push(this); } var i = siblings.indexOf(this); if (i > -1) { return reverse ? siblings.length - i - 1 : i; } return -1; } }, { key: 'closest', value: function closest(sel) { var cur = this; while (cur && cur != this.top) { if (_matchUtil2.default.nci(sel, cur)) { cur = cur.parent; continue; } return cur; } } }, { key: '__renderProp', value: function __renderProp(k, v) { var self = this; var res = ''; // onxxx侦听处理 if (/^on[a-zA-Z]/.test(k)) { self.__renderPropEventDelay = self.__renderPropEventDelay || []; self.__renderPropEventDelay.push({ k: k.slice(2).toLowerCase(), v: v }); } // Obj类型绑定处理 else if (v instanceof _Obj2.default) { // 特殊html不转义 if (k == 'dangerouslySetInnerHTML') { return ''; } var s = v.toString(true); if (k == 'className') { k = 'class'; } else if (k == 'htmlFor') { k = 'for'; } self.__cache[k] = s; // 特殊属性根据类型输出或是在DOM后设置prop var special = _attr2.default.special(self.__name, k); switch (special) { case _attr2.default.RENDER_EXIST: if (v.v) { res = ' ' + k + '="' + s + '"'; } break; case _attr2.default.RENDER_DOM: self.once(_Event2.default.DOM, function () { self.__updateAttr(k, v.v); }); break; default: res = ' ' + k + '="' + s + '"'; break; } } else { var s = Array.isArray(v) ? _util2.default.joinSourceArray(v) : _util2.default.stringify(v); if (k == 'dangerouslySetInnerHTML') { return ''; } if (k == 'className') { k = 'class'; } else if (k == 'htmlFor') { k = 'for'; } self.__cache[k] = s; // 特殊属性根据类型输出或是在DOM后设置prop var special = _attr2.default.special(self.__name, k); switch (special) { case _attr2.default.RENDER_EXIST: if (v) { res = ' ' + k + '="' + _util2.default.encodeHtml(s, true) + '"'; } break; case _attr2.default.RENDER_DOM: self.once(_Event2.default.DOM, function () { self.__updateAttr(k, v); }); break; default: res = ' ' + k + '="' + _util2.default.encodeHtml(s, true) + '"'; break; } } // 使用jaw导入样式时不输出class和id,以migi-class和migi-id取代之 if (self.__style) { switch (k) { case 'class': case 'id': res = ' ' + 'migi-' + res.slice(1); break; } } return res; } }, { key: '__renderChildren', value: function __renderChildren() { var self = this; var res = ''; for (var i = 0, len = self.children.length; i < len; i++) { res += renderChild(self.children[i]); } return res; } }, { key: '__checkListener', value: function __checkListener() { var self = this; if (self.__name == 'input') { if (self.props.hasOwnProperty('value')) { var item = self.props.value; if (item instanceof _Obj2.default && item.vBind) { self.once(_Event2.default.DOM, function () { var type = (self.__cache.type || '').toLowerCase(); function cb(e) { (0, _fixEvent2.default)(e); var v = e.target.value; if (type == 'number') { v = parseFloat(v); } item.vBind(v); } switch (type) { // 一些无需联动 // case 'button': // case 'hidden': // case 'image': // case 'file': // case 'reset': // case 'submit': // break; // 只需侦听change case 'checkbox': case 'radio': case 'range': case 'color': self.__addListener('change', cb); break; // 其它无需change,但input等 default: self.__addListener(['input', 'paste', 'cut', 'change'], cb); break; } }); } } else if (self.props.hasOwnProperty('checked')) { var item = self.props.checked; if (item instanceof _Obj2.default && item.vBind) { self.once(_Event2.default.DOM, function () { function cb(e) { (0, _fixEvent2.default)(e); var v = e.target.checked; item.vBind(v); } var type = self.__cache.type || ''; switch (type.toLowerCase()) { case 'checkbox': case 'radio': self.__addListener('change', cb); break; } }); } } } else if (self.__name == 'option') { if (self.props.hasOwnProperty('selected')) { var item = self.props.selected; if (item instanceof _Obj2.default && item.vBind) { self.once(_Event2.default.DOM, function () { function cb(e) { (0, _fixEvent2.default)(e); var v = e.target.selected; item.vBind(v); } self.__addListener('change', cb); }); } } } // textarea的value在标签的childNodes里,这里只处理单一child情况 // children有多个其中一个是text有歧义,忽视 else if (self.__name == 'textarea') { if (self.children.length == 1) { var child = self.children[0]; if (child instanceof _Obj2.default && child.vBind) { self.once(_Event2.default.DOM, function () { function cb(e) { (0, _fixEvent2.default)(e); var v = e.target.value; child.vBind(v); } self.__addListener(['input', 'paste', 'cut', 'change'], cb); }); } } } if (self.__renderPropEventDelay) { self.__renderPropEventDelay.forEach(function (item) { self.once(_Event2.default.DOM, function () { self.__addEvt(item.k, item.v); }); }); self.__renderPropEventDelay = null; } } }, { key: '__addEvt', value: function __addEvt(name, v) { var self = this; self.__addListener(name, function (e) { (0, _fixEvent2.default)(e); var target = e.target; var uid = target.getAttribute('migi-uid'); var tvd = _hash2.default.get(uid); if (v instanceof _Cb2.default && _util2.default.isFunction(v.cb)) { return v.cb.call(v.context, e, self, tvd); } else if (_util2.default.isFunction(v)) { return v(e, self, tvd); } else if (Array.isArray(v)) { var ret; v.forEach(function (item, i) { var cb = item[1]; var res = (0, _delegate2.default)(e, item[0], self); if (res[0]) { if (cb instanceof _Cb2.default && _util2.default.isFunction(cb.cb)) { if (i) { cb.cb.call(cb.context, e, self, res[1], tvd); } else { ret = cb.cb.call(cb.context, e, self, res[1], tvd); } } else if (_util2.default.isFunction(cb)) { if (i) { cb(e, self, res[1], tvd); } else { ret = cb(e, self, res[1], tvd); } } } }); return ret; } }); } }, { key: '__addListener', value: function __addListener(name, cb) { var self = this; if (Array.isArray(name)) { for (var i = 0, len = name.length; i < len; i++) { self.__addListener(name[i], cb); } } else { // 一般没有event,也就不生成对象防止diff比对 self.__listener = self.__listener || []; if (name == 'tap') { name = 'click'; } var elem = self.element; // touch特殊对待 if (TOUCH.hasOwnProperty(name)) { (0, _touch2.default)(this, name, cb, self.__listener); return; } // 记录下来留待清除 self.__listener.push([name, cb]); elem.addEventListener(_eventCaseName2.default[name] || name, cb); // onLoad可能因为缓存不发生 if (name == 'load' && elem.complete) { var event = document.createEvent('Event'); event.initEvent('load', true, true); elem.dispatchEvent(event); } } } }, { key: '__removeListener', value: function __removeListener() { var self = this; if (self.__listener) { var elem = self.element; for (var i = self.__listener.length - 1; i >= 0; i--) { var arr = self.__listener[i]; elem.removeEventListener(arr[0], arr[1]); } self.__listener = null; } } }, { key: 'find', value: function find(selector) { if (_util2.default.isFunction(selector)) { return _find(selector, this.children); } if (this.element) { var node = this.element.querySelector(convertSelector(selector)); var uid = node.getAttribute('migi-uid'); return _hash2.default.get(uid) || null; } return null; } }, { key: 'findAll', value: function findAll(selector) { if (_util2.default.isFunction(selector)) { return _findAll(selector, this.children); } var res = []; if (this.element) { var nodes = this.element.querySelectorAll(convertSelector(selector)); Array.from(nodes).forEach(function (node) { if (node) { var uid = node.getAttribute('migi-uid'); var vd = _hash2.default.get(uid) || null; if (vd) { res.push(vd); } } }); } return res; } // @override }, { key: '__onDom', value: function __onDom() { _get(VirtualDom.prototype.__proto__ || Object.getPrototypeOf(VirtualDom.prototype), '__onDom', this).call(this); var self = this; // start标明真实DOM索引,因为相邻的文本会合并为一个text节点 var option = { start: 0, first: true }; self.__checkBlank(self.children, option); // 可能最后一个是空白text,或没有children,需特殊判断下插入 if (option.empty || option.first) { self.__insertBlank(option.start); } } }, { key: '__checkBlank', value: function __checkBlank(item, option) { var self = this; if (Array.isArray(item) && item.length) { for (var i = 0, len = item.length; i < len; i++) { self.__checkBlank(item[i], option); } } else if (_util2.default.isDom(item)) { // 前面的连续的空白节点需插入一个空TextNode if (option.empty) { self.__insertBlank(option.start); } // 递归通知DOM事件,增加start索引 option.start++; // 前方文本节点需再增1次,因为文本节点自身不涉及start索引逻辑 if (option.prev == _type2.default.TEXT) { option.start++; } option.prev = _type2.default.DOM; option.empty = false; option.first = false; item.emit(_Event2.default.DOM); } else if (item instanceof _Obj2.default) { self.__checkBlank(item.v, option); } else if (isEmptyText(item)) { // 前方如有兄弟文本节点,无需插入,否则先记录empty,等后面检查是否有非空text出现,再插入空白节点 if (option.prev == _type2.default.TEXT) { return; } option.empty = true; option.prev = _type2.default.TEXT; option.first = false; } // 一旦是个非空text,之前记录的空text将无效,因为相邻的text会合并为一个text节点 else { option.empty = false; option.prev = _type2.default.TEXT; option.first = false; } } }, { key: '__insertBlank', value: function __insertBlank(start) { var blank = document.createTextNode(''); var elem = this.element; var cns = elem.childNodes; // 可能仅一个空文本节点,或最后一个空文本节点 var length = cns.length; if (!length || start >= length) { elem.appendChild(blank); } // 插入 else { elem.insertBefore(blank, cns[start]); } } // @override }, { key: '__onData', value: function __onData(k, opt) { var self = this; // 尚未添加到dom时无效 if (!self.dom) { return; } // 联动属性值 for (var i = 0, len = self.__props.length; i < len; i++) { var item = self.__props[i]; var key = item[0]; item = item[1]; if (item instanceof _Obj2.default) { var change = false; var vk = Array.isArray(k) ? 1 : 0; var ok = Array.isArray(item.k) ? 2 : 0; switch (vk | ok) { case 0: change = k == item.k; break; case 1: change = k.indexOf(item.k) > -1; break; case 2: change = item.k.indexOf(k) > -1; break; case 3: var hash = {}; for (var j = k.length - 1; j >= 0; j--) { hash[k[j]] = true; } for (var temp = item.k, j = 0, len = temp.length; j < len; j++) { if (hash.hasOwnProperty(temp[j])) { change = true; break; } } break; } if (change) { var ov = item.v; if (item.update(ov)) { self.__updateAttr(key, item.v); } } } } // 利用索引更新,子节点可能为文本、Component、VirtualDom,以及数组 // 其中只有文本节点需要自己更新,记录其索引,组件和VirtualDom递归通知更新 // 由于渲染时相邻的文本变量和String文本同为一个文本节点,因此start为真实DOM的索引,history和record为vd索引 // 当文本节点时start不更新 // Obj类型的判断type和count,及为文本时是否为空 var record = { start: 0, range: [], history: [], first: true }; var children = self.children; for (var index = 0, len = children.length; index < len; index++) { var child = children[index]; record.index = [index]; self.__checkObj(k, child, record, opt); } if (record.range.length) { // textarea特殊判断 if (self.__name == 'textarea') { self.__updateAttr('value', _range2.default.value(record.range[0], self.children)); return; } for (var i = 0, len = record.range.length; i < len; i++) { _range2.default.update(record.range[i], self.children, self.element); } } } // record.first标明是否第一个,因为child为数组时会展开,当child不是第1个时其展开项都有prev }, { key: '__checkObj', value: function __checkObj(k, child, record, opt) { var self = this; // 当Component和VirtualDom则start++,且前面是非空文本节点时再++,因为有2个节点 // 文本节点本身不会增加索引,因为可能有相邻的 if (child instanceof _Obj2.default) { // 可能Obj的关联是个列表,触发的变量name也是列表 var change = false; var vk = Array.isArray(k) ? 1 : 0; var ok = Array.isArray(child.k) ? 2 : 0; switch (vk | ok) { case 0: change = k == child.k; break; case 1: change = k.indexOf(child.k) > -1; break; case 2: change = child.k.indexOf(k) > -1; break; case 3: var hash = {}; for (var i = k.length - 1; i >= 0; i--) { hash[k[i]] = true; } for (var temp = child.k, i = 0, len = temp.length; i < len; i++) { if (hash.hasOwnProperty(temp[i])) { change = true; break; } } break; } // 当可能发生变化时才进行比对 if (change) { var ov = child.v; // 对比是否真正发生变更 if (child.update(ov)) { _domDiff2.default.diff(this, this.element, ov, child.v, record, _dev2.default.optimizeArrayDiff && child.single && opt); } else { self.__checkObj(k, child.v, record, opt); } } else { self.__checkObj(k, child.v, record, opt); } } // 递归通知,增加索引 else if (_util2.default.isDom(child)) { if (child instanceof VirtualDom) { child.__onData(k, opt); } // bindProperty #37 else { child.__notifyBindProperty(k); } record.start++; // 前面的文本再加一次索引 if (!record.first && record.prev == _type2.default.TEXT) { record.start++; } record.state = _type2.default.DOM_TO_DOM; record.prev = _type2.default.DOM; } else if (Array.isArray(child)) { if (child.length) { // 数组类型记得递归记录history索引,结束后出栈 record.index.push(0); for (var i = 0, len = child.length; i < len; i++) { var item = child[i]; record.index[record.index.length - 1] = i; // 第1个同时作为children的第1个要特殊处理 self.__checkObj(k, item, record, opt); } record.index.pop(); } // 注意空数组算text类型 else { _domDiff2.default.checkText(this.element, child, record); if (record.first || record.prev == _type2.default.DOM) { _domDiff2.default.recordRange(record); } record.state = _type2.default.TEXT_TO_TEXT; record.prev = _type2.default.TEXT; } } // 其它情况为文本节点或者undefined忽略 else { _domDiff2.default.checkText(this.element, child, record); if (record.first || record.prev == _type2.default.DOM) { _domDiff2.default.recordRange(record); } record.state = _type2.default.TEXT_TO_TEXT; record.prev = _type2.default.TEXT; } record.first = false; } // TODO: 一个神奇的现象,实体字符作为attr在初始化时作为String拼接和在setAttribute中表现不一致 // 如&nbsp;会成为charCode 160的Non-breaking space,而非32的Normal space // 但是setAttribute会保留实体字符形式 }, { key: '__updateAttr', value: function __updateAttr(k, v) { if (k == 'dangerouslySetInnerHTML') { if (v === null || v === undefined) { v = ''; } this.element.innerHTML = _util2.default.stringify(v); // 清空后创建空字符节点 this.__insertBlank(0); return; } _attr2.default.update(this.__name, this.element, k, v, this.__style); this.__cache[k] = v; // 使用了jaw内联解析css if (this.__style) { this.__updateStyle(); } } }, { key: '__match', value: function __match(first) { var inline = this.__cache.style || ''; // 预处理class和id,class分为数组形式,id判断#开头 this.__initCI(); var matches = (0, _match2.default)(this.__names, this.__classes, this.__ids, this.__style || { default: {} }, this, first); // 本身的inline最高优先级追加到末尾 return matches + inline; } }, { key: '__initCI', value: function __initCI() { var p = this.parent; if (p instanceof VirtualDom) { this.__classes = p.__classes.slice(); this.__ids = p.__ids.slice(); } else { this.__classes = []; this.__ids = []; } // 预处理class和id,class分为数组形式,id判断#开头 this.__classes.push(_matchUtil2.default.splitClass(this.__cache['class'])); this.__ids.push(_matchUtil2.default.preId(this.__cache.id)); } }, { key: '__updateStyle', value: function __updateStyle(first) { var s = this.__match(first); if (this.element.getAttribute('style') != s) { this.element.setAttribute('style', s); } // diff调用初始化nvd时自上而下,忽略children if (first) { return; } for (var i = this.children.length - 1; i >= 0; i--) { var child = this.children[i]; if (child instanceof VirtualDom) { child.__updateStyle(); } } } }, { key: '__init', value: function __init(name, children) { var self = this; self.__selfClose = _selfClose2.default.hasOwnProperty(name); childParent(children, self); } // @Overwrite }, { key: '__reset', value: function __reset(uid, name) { var props = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; var children = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : []; _get(VirtualDom.prototype.__proto__ || Object.getPrototypeOf(VirtualDom.prototype), '__reset', this).call(this, uid, name, props, children); this.__init(name, children); this.__hasDes = false; return this; } }, { key: '__destroy', value: function __destroy() { if (this.__onHover || this.__outHover) { if (this.element) { this.element.removeEventListener('mouseenter', this.__onHover); this.element.removeEventListener('mouseleave', this.__outHover); } } this.__hash = {}; this.__cache = null; this.__names = null; this.__classes = null; this.__ids = null; this.__hover = false; this.__active = false; this.__listener = null; this.__parent = null; this.__top = null; this.__dom = false; this.__style = null; this.__element = null; this.__renderPropEventDelay = null; return this; } // @Overwrite }, { key: 'clean', value: function clean() { _get(VirtualDom.prototype.__proto__ || Object.getPrototypeOf(VirtualDom.prototype), 'clean', this).call(this); this.__renderPropEventDelay = null; this.__removeListener(); this.__names = null; this.__classes = null; this.__ids = null; this.__hover = false; this.__active = false; } }, { key: 'names', get: function get() { return this.__names || (this.__names = []); } }, { key: 'element', get: function get() { return this.__element || (this.__element = document.querySelector(this.__name + '[migi-uid="' + this.__uid + '"]')); } }, { key: 'style', get: function get() { return this.__style; }, set: function set(v) { var self = this; self.__style = v; if (self.parent instanceof VirtualDom) { self.__names = self.parent.names.slice(); } else { self.__names = []; } self.__names.push(self.__name); for (var i = 0, len = self.children.length; i < len; i++) { childStyle(self.children[i], v); } } }]); return VirtualDom; }(_Element3.default); // 静态文本节点,包括空、undefined、null、空数组 function isEmptyText(item) { return item === undefined || item === null || !item.toString(); } function renderChild(child) { if (child instanceof _Element3.default || child instanceof _Obj2.default) { return child.toString(); } if (Array.isArray(child)) { var res = ''; for (var i = 0, len = child.length; i < len; i++) { res += renderChild(child[i]); } return res; } return _util2.default.encodeHtml(_util2.default.stringify(child)); } function childParent(child, parent) { if (Array.isArray(child)) { for (var i = 0, len = child.length; i < len; i++) { childParent(child[i], parent); } } else if (child instanceof _Element3.default) { child.__parent = parent; } else if (child instanceof _Obj2.default) { childParent(child.v, parent); } } function childStyle(child, style) { if (Array.isArray(child)) { for (var i = 0, len = child.length; i < len; i++) { childStyle(child[i], style); } } else if (child instanceof VirtualDom) { child.style = style; } else if (child instanceof _Obj2.default) { childStyle(child.v, style); } } function childEmpty(child) { var res = true; if (Array.isArray(child)) { for (var i = 0, len = child.length; i < len; i++) { res = childEmpty(child[i]); if (!res) { break; } } } else if (child instanceof _Element3.default) { res = false; } else if (child instanceof _Obj2.default) { res = childEmpty(child.v); } else { res = isEmptyText(child); } return res; } function getPrev(child, target, res, cb) { if (Array.isArray(child)) { for (var i = 0, len = child.length; i < len; i++) { getPrev(child[i], target, res, cb); if (res.done) { break; } } } else if (child instanceof _Element3.default) { if (target == child) { res.done = true; return; } cb(child); } else if (child instanceof _Obj2.default) { getPrev(child.v, target, res, cb); } } function getNext(child, target, res, cb) { if (Array.isArray(child)) { for (var i = 0, len = child.length; i < len; i++) { getNext(child[i], target, res, cb); if (res.done) { break; } } } else if (child instanceof _Element3.default) { if (target == child) { res.start = true; } else if (res.start) { cb(child); } } else if (child instanceof _Obj2.default) { getNext(child.v, target, res, cb); } } function allChildren(child) { var res = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; if (Array.isArray(child)) { for (var i = 0, len = child.length; i < len; i++) { allChildren(child[i], res); } } else if (child instanceof _Element3.default) { res.push(child); } else if (child instanceof _Obj2.default) { allChildren(child.v, res); } return res; } exports.default = VirtualDom;});