This repository has been archived on 2023-08-29. You can view files and clone it, but cannot push or open issues/pull-requests.
yutent
/
anot.js
Archived
1
0
Fork 0
anot.js/src/02-core.js

541 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

let Anot = function(el) {
//创建jQuery式的无new 实例化结构
return new Anot.init(el)
}
/*视浏览器情况采用最快的异步回调*/
Anot.nextTick = new function() {
// jshint ignore:line
let tickImmediate = window.setImmediate
let tickObserver = window.MutationObserver
if (tickImmediate) {
return tickImmediate.bind(window)
}
let queue = []
function callback() {
let n = queue.length
for (let i = 0; i < n; i++) {
queue[i]()
}
queue = queue.slice(n)
}
if (tickObserver) {
let node = document.createTextNode('anot')
new tickObserver(callback).observe(node, { characterData: true }) // jshint ignore:line
let bool = false
return function(fn) {
queue.push(fn)
bool = !bool
node.data = bool
}
}
return function(fn) {
setTimeout(fn, 4)
}
}() // jshint ignore:line
/*********************************************************************
* Anot的静态方法定义区 *
**********************************************************************/
Anot.type = function(obj) {
//取得目标的类型
if (obj == null) {
return String(obj)
}
// 早期的webkit内核浏览器实现了已废弃的ecma262v4标准可以将正则字面量当作函数使用因此typeof在判定正则时会返回function
return typeof obj === 'object' || typeof obj === 'function'
? class2type[serialize.call(obj)] || 'object'
: typeof obj
}
Anot.PropsTypes = function(type) {
this.type = 'PropsTypes'
this.checkType = type
}
Anot.PropsTypes.prototype = {
toString: function() {
return ''
},
check: function(val) {
this.result = Anot.type(val)
return this.result === this.checkType
},
call: function() {
return this.toString()
}
}
Anot.PropsTypes.isString = function() {
return new this('string')
}
Anot.PropsTypes.isNumber = function() {
return new this('number')
}
Anot.PropsTypes.isFunction = function() {
return new this('function')
}
Anot.PropsTypes.isArray = function() {
return new this('array')
}
Anot.PropsTypes.isObject = function() {
return new this('object')
}
Anot.PropsTypes.isBoolean = function() {
return new this('boolean')
}
/*判定是否是一个朴素的javascript对象Object不是DOM对象不是BOM对象不是自定义类的实例*/
Anot.isPlainObject = function(obj) {
// 简单的 typeof obj === "object"检测会致使用isPlainObject(window)在opera下通不过
return (
serialize.call(obj) === '[object Object]' &&
Object.getPrototypeOf(obj) === oproto
)
}
let VMODELS = (Anot.vmodels = {}) //所有vmodel都储存在这里
Anot.init = function(source) {
if (Anot.isPlainObject(source)) {
let $id = source.$id
let vm = null
if (!$id) {
log('warning: vm必须指定id')
}
vm = modelFactory(Object.assign({ props: {} }, source))
vm.$id = $id
VMODELS[$id] = vm
Anot.nextTick(function() {
let $elem = document.querySelector('[anot=' + vm.$id + ']')
if ($elem) {
if ($elem === DOC.body) {
scanTag($elem, [])
} else {
let _parent = $elem
while ((_parent = _parent.parentNode)) {
if (_parent.__VM__) {
break
}
}
scanTag($elem.parentNode, _parent ? [_parent.__VM__] : [])
}
}
})
return vm
} else {
this[0] = this.element = source
}
}
Anot.fn = Anot.prototype = Anot.init.prototype
//与jQuery.extend方法可用于浅拷贝深拷贝
Anot.mix = Anot.fn.mix = function() {
let options,
name,
src,
copy,
copyIsArray,
clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false
// 如果第一个参数为布尔,判定是否深拷贝
if (typeof target === 'boolean') {
deep = target
target = arguments[1] || {}
i++
}
//确保接受方为一个复杂的数据类型
if (typeof target !== 'object' && Anot.type(target) !== 'function') {
target = {}
}
//如果只有一个参数那么新成员添加于mix所在的对象上
if (i === length) {
target = this
i--
}
for (; i < length; i++) {
//只处理非空参数
if ((options = arguments[i]) != null) {
for (name in options) {
src = target[name]
copy = options[name]
// 防止环引用
if (target === copy) {
continue
}
if (
deep &&
copy &&
(Anot.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))
) {
if (copyIsArray) {
copyIsArray = false
clone = src && Array.isArray(src) ? src : []
} else {
clone = src && Anot.isPlainObject(src) ? src : {}
}
target[name] = Anot.mix(deep, clone, copy)
} else if (copy !== void 0) {
target[name] = copy
}
}
}
}
return target
}
function cacheStore(tpye, key, val) {
if (this.type(key) === 'object') {
for (let i in key) {
window[tpye].setItem(i, key[i])
}
return
}
switch (arguments.length) {
case 2:
return window[tpye].getItem(key)
case 3:
if ((this.type(val) == 'string' && val.trim() === '') || val === null) {
window[tpye].removeItem(key)
return
}
if (this.type(val) !== 'object' && this.type(val) !== 'array') {
window[tpye].setItem(key, val.toString())
} else {
window[tpye].setItem(key, JSON.stringify(val))
}
break
}
}
/*判定是否类数组如节点集合纯数组arguments与拥有非负整数的length属性的纯JS对象*/
function isArrayLike(obj) {
if (obj && typeof obj === 'object') {
let n = obj.length,
str = serialize.call(obj)
if (/(Array|List|Collection|Map|Arguments)\]$/.test(str)) {
return true
} else if (str === '[object Object]' && n === n >>> 0) {
return true //由于ecma262v5能修改对象属性的enumerable因此不能用propertyIsEnumerable来判定了
}
}
return false
}
Anot.mix({
rword: rword,
subscribers: subscribers,
version: '1.0.0',
log: log,
ui: {}, //仅用于存放组件版本信息等
slice: function(nodes, start, end) {
return aslice.call(nodes, start, end)
},
noop: noop,
/*如果不用Error对象封装一下str在控制台下可能会乱码*/
error: function(str, e) {
throw new (e || Error)(str) // jshint ignore:line
},
/* Anot.range(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Anot.range(1, 11)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Anot.range(0, 30, 5)
=> [0, 5, 10, 15, 20, 25]
Anot.range(0, -10, -1)
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
Anot.range(0)
=> []*/
range: function(start, end, step) {
// 用于生成整数数组
step || (step = 1)
if (end == null) {
end = start || 0
start = 0
}
let index = -1,
length = Math.max(0, Math.ceil((end - start) / step)),
result = new Array(length)
while (++index < length) {
result[index] = start
start += step
}
return result
},
deepCopy: toJson,
eventHooks: {},
/*绑定事件*/
bind: function(el, type, fn, phase) {
let hooks = Anot.eventHooks
type = type.split(',')
Anot.each(type, function(i, t) {
t = t.trim()
let hook = hooks[t]
if (typeof hook === 'object') {
type = hook.type || type
phase = hook.phase || !!phase
fn = hook.fix ? hook.fix(el, fn) : fn
}
el.addEventListener(t, fn, phase)
})
return fn
},
/*卸载事件*/
unbind: function(el, type, fn, phase) {
let hooks = Anot.eventHooks
type = type.split(',')
fn = fn || noop
Anot.each(type, function(i, t) {
t = t.trim()
let hook = hooks[t]
if (typeof hook === 'object') {
type = hook.type || type
phase = hook.phase || !!phase
}
el.removeEventListener(t, fn, phase)
})
},
/*读写删除元素节点的样式*/
css: function(node, name, value) {
if (node instanceof Anot) {
node = node[0]
}
var prop = /[_-]/.test(name) ? camelize(name) : name
var fn
name = Anot.cssName(prop) || prop
if (value === void 0 || typeof value === 'boolean') {
//获取样式
fn = cssHooks[prop + ':get'] || cssHooks['@:get']
if (name === 'background') {
name = 'backgroundColor'
}
var val = fn(node, name)
return value === true ? +val || 0 : val
} else if (value === '') {
//请除样式
node.style[name] = ''
} else {
//设置样式
if (value == null || value !== value) {
return
}
if (isFinite(value) && !Anot.cssNumber[prop]) {
value += 'px'
}
fn = cssHooks[prop + ':set'] || cssHooks['@:set']
fn(node, name, value)
}
},
/*遍历数组与对象,回调的第一个参数为索引或键名,第二个或元素或键值*/
each: function(obj, fn) {
if (obj) {
//排除null, undefined
let i = 0
if (isArrayLike(obj)) {
for (let n = obj.length; i < n; i++) {
if (fn(i, obj[i]) === false) break
}
} else {
for (i in obj) {
if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) {
break
}
}
}
}
},
Array: {
/*只有当前数组不存在此元素时只添加它*/
ensure: function(target, item) {
if (target.indexOf(item) === -1) {
return target.push(item)
}
},
/*移除数组中指定位置的元素,返回布尔表示成功与否*/
removeAt: function(target, index) {
return !!target.splice(index, 1).length
},
/*移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否*/
remove: function(target, item) {
let index = target.indexOf(item)
if (~index) return Anot.Array.removeAt(target, index)
return false
}
},
/**
* [ls localStorage操作]
* @param {[type]} key [键名]
* @param {[type]} val [键值,为空时删除]
* @return
*/
ls: function() {
let args = aslice.call(arguments, 0)
args.unshift('localStorage')
return cacheStore.apply(this, args)
},
ss: function() {
let args = aslice.call(arguments, 0)
args.unshift('sessionStorage')
return cacheStore.apply(this, args)
},
/**
* [cookie cookie 操作 ]
* @param key [cookie名]
* @param val [cookie值]
* @param {[json]} opt [有效期,域名,路径等]
* @return {[boolean]} [读取时返回对应的值写入时返回true]
*/
cookie: function(key, val, opt) {
if (arguments.length > 1) {
if (!key) {
return
}
//设置默认的参数
opt = opt || {}
opt = Object.assign(
{
expires: '',
path: '/',
domain: document.domain,
secure: ''
},
opt
)
if ((this.type(val) == 'string' && val.trim() === '') || val === null) {
document.cookie =
encodeURIComponent(key) +
'=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=' +
opt.domain +
'; path=' +
opt.path
return true
}
if (opt.expires) {
switch (opt.expires.constructor) {
case Number:
opt.expires =
opt.expires === Infinity
? '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
: '; max-age=' + opt.expires
break
case String:
opt.expires = '; expires=' + opt.expires
break
case Date:
opt.expires = '; expires=' + opt.expires.toUTCString()
break
}
}
document.cookie =
encodeURIComponent(key) +
'=' +
encodeURIComponent(val) +
opt.expires +
'; domain=' +
opt.domain +
'; path=' +
opt.path +
'; ' +
opt.secure
return true
} else {
if (!key) {
return document.cookie
}
return (
decodeURIComponent(
document.cookie.replace(
new RegExp(
'(?:(?:^|.*;)\\s*' +
encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') +
'\\s*\\=\\s*([^;]*).*$)|^.*$'
),
'$1'
)
) || null
)
}
},
//获取url的参数
search: function(key) {
key += ''
let uri = location.search
if (!key || !uri) {
return null
}
uri = decodeURIComponent(uri)
uri = uri.slice(1)
uri = uri.split('&')
let obj = {}
for (let i = 0, item; (item = uri[i++]); ) {
let tmp = item.split('=')
tmp[1] = tmp.length < 2 ? null : tmp[1]
tmp[1] = tmp[1]
if (obj.hasOwnProperty(tmp[0])) {
if (typeof obj[tmp[0]] === 'object') {
obj[tmp[0]].push(tmp[1])
} else {
obj[tmp[0]] = [obj[tmp[0]]]
obj[tmp[0]].push(tmp[1])
}
} else {
obj[tmp[0]] = tmp[1]
}
}
return obj.hasOwnProperty(key) ? obj[key] : null
},
//复制文本到粘贴板
copy: function(txt) {
if (!DOC.queryCommandSupported || !DOC.queryCommandSupported('copy')) {
return log('该浏览器不支持复制到粘贴板')
}
let ta = DOC.createElement('textarea')
ta.textContent = txt
ta.style.position = 'fixed'
ta.style.bottom = '-1000px'
DOC.body.appendChild(ta)
ta.select()
try {
DOC.execCommand('copy')
} catch (err) {
log('复制到粘贴板失败', err)
}
DOC.body.removeChild(ta)
}
})
let bindingHandlers = (Anot.bindingHandlers = {})
let bindingExecutors = (Anot.bindingExecutors = {})
let directives = (Anot.directives = {})
Anot.directive = function(name, obj) {
bindingHandlers[name] = obj.init = obj.init || noop
bindingExecutors[name] = obj.update = obj.update || noop
return (directives[name] = obj)
}
Anot 是Anot not only templateEngine的缩写。 它是一款迷你,易用、高性能的前端MVVM框架, fork于avalon。进行了大量的重构,精简部分冗余的API, 同时针对组件拓展进行了优化。
JavaScript 100%