179 lines
5.1 KiB
JavaScript
179 lines
5.1 KiB
JavaScript
//将所有远程加载的模板,以字符串形式存放到这里
|
||
var templatePool = (Anot.templateCache = {})
|
||
|
||
function getTemplateContainer(binding, id, text) {
|
||
var div = binding.templateCache && binding.templateCache[id]
|
||
if (div) {
|
||
var dom = DOC.createDocumentFragment(),
|
||
firstChild
|
||
while ((firstChild = div.firstChild)) {
|
||
dom.appendChild(firstChild)
|
||
}
|
||
return dom
|
||
}
|
||
return Anot.parseHTML(text)
|
||
}
|
||
function nodesToFrag(nodes) {
|
||
var frag = DOC.createDocumentFragment()
|
||
for (var i = 0, len = nodes.length; i < len; i++) {
|
||
frag.appendChild(nodes[i])
|
||
}
|
||
return frag
|
||
}
|
||
|
||
function _fetch(url) {
|
||
var xhr = new XMLHttpRequest()
|
||
var defer = Promise.defer()
|
||
xhr.open('GET', url, true)
|
||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
|
||
xhr.responseType = 'text'
|
||
xhr.onreadystatechange = function() {
|
||
if (this.readyState === 4) {
|
||
if (this.status >= 200 && this.status < 400) {
|
||
defer.resolve(this.response)
|
||
} else {
|
||
defer.reject(this)
|
||
}
|
||
}
|
||
}
|
||
xhr.send(null)
|
||
return defer.promise
|
||
}
|
||
|
||
Anot.directive('include', {
|
||
init: directives.attr.init,
|
||
update: function(val) {
|
||
if (!val) {
|
||
return
|
||
}
|
||
|
||
var binding = this
|
||
var elem = this.element
|
||
var vmodels = binding.vmodels
|
||
var loaded = binding.includeLoaded // 加载完的回调
|
||
var rendered = binding.includeRendered // 渲染完的回调
|
||
var effectClass = binding.effectName && binding.effectClass // 是否开启动画
|
||
var templateCache = binding.templateCache // 是否开启 缓存
|
||
var outer = binding.includeReplace // 是否替换容器
|
||
var target = outer ? elem.parentNode : elem
|
||
var _ele = binding._element // replace binding.element === binding.end
|
||
|
||
binding.recoverNodes = binding.recoverNodes || Anot.noop
|
||
|
||
var scanTemplate = function(text) {
|
||
var _stamp = (binding._stamp = Date.now()) // 过滤掉频繁操作
|
||
if (loaded) {
|
||
var newText = loaded.apply(target, [text].concat(vmodels))
|
||
if (typeof newText === 'string') {
|
||
text = newText
|
||
}
|
||
}
|
||
if (rendered) {
|
||
checkScan(
|
||
target,
|
||
function() {
|
||
rendered.call(target)
|
||
},
|
||
NaN
|
||
)
|
||
}
|
||
var lastID = binding.includeLastID || '_default' // 默认
|
||
|
||
binding.includeLastID = val
|
||
var leaveEl =
|
||
(templateCache && templateCache[lastID]) ||
|
||
DOC.createElement(elem.tagName || binding._element.tagName) // 创建一个离场元素
|
||
|
||
if (effectClass) {
|
||
leaveEl.className = effectClass
|
||
target.insertBefore(leaveEl, binding.start) // 插入到start之前,防止被错误的移动
|
||
}
|
||
|
||
// cache or animate,移动节点
|
||
;(templateCache || {})[lastID] = leaveEl
|
||
var fragOnDom = binding.recoverNodes() // 恢复动画中的节点
|
||
if (fragOnDom) {
|
||
target.insertBefore(fragOnDom, binding.end)
|
||
}
|
||
while (true) {
|
||
var node = binding.start.nextSibling
|
||
if (node && node !== leaveEl && node !== binding.end) {
|
||
leaveEl.appendChild(node)
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
|
||
// 元素退场
|
||
Anot.effect.remove(
|
||
leaveEl,
|
||
target,
|
||
function() {
|
||
if (templateCache) {
|
||
// write cache
|
||
if (_stamp === binding._stamp) ifGroup.appendChild(leaveEl)
|
||
}
|
||
},
|
||
binding
|
||
)
|
||
|
||
var enterEl = target,
|
||
before = Anot.noop,
|
||
after = Anot.noop
|
||
|
||
var fragment = getTemplateContainer(binding, val, text)
|
||
var nodes = Anot.slice(fragment.childNodes)
|
||
|
||
if (outer && effectClass) {
|
||
enterEl = _ele
|
||
enterEl.innerHTML = '' // 清空
|
||
enterEl.setAttribute('skip', '')
|
||
target.insertBefore(enterEl, binding.end.nextSibling) // 插入到bingding.end之后避免被错误的移动
|
||
before = function() {
|
||
enterEl.insertBefore(fragment, null) // 插入节点
|
||
}
|
||
after = function() {
|
||
binding.recoverNodes = Anot.noop
|
||
if (_stamp === binding._stamp) {
|
||
fragment = nodesToFrag(nodes)
|
||
target.insertBefore(fragment, binding.end) // 插入真实element
|
||
scanNodeArray(nodes, vmodels)
|
||
}
|
||
if (enterEl.parentNode === target) target.removeChild(enterEl) // 移除入场动画元素
|
||
}
|
||
binding.recoverNodes = function() {
|
||
binding.recoverNodes = Anot.noop
|
||
return nodesToFrag(nodes)
|
||
}
|
||
} else {
|
||
before = function() {
|
||
//新添加元素的动画
|
||
target.insertBefore(fragment, binding.end)
|
||
scanNodeArray(nodes, vmodels)
|
||
}
|
||
}
|
||
|
||
Anot.effect.apply(enterEl, 'enter', before, after)
|
||
}
|
||
|
||
if (templatePool[val]) {
|
||
Anot.nextTick(function() {
|
||
scanTemplate(templatePool[val])
|
||
})
|
||
} else {
|
||
_fetch(val)
|
||
.then(text => {
|
||
templatePool[val] = text
|
||
scanTemplate(text)
|
||
})
|
||
.catch(err => {
|
||
log(
|
||
':include load [' + val + '] error\n%c%s',
|
||
'color:#f30',
|
||
`获取网络资源出错, ${err.status} (${err.statusText})`
|
||
)
|
||
})
|
||
}
|
||
}
|
||
})
|