Compare commits
No commits in common. "master" and "2.0.0" have entirely different histories.
|
@ -3,7 +3,6 @@
|
|||
.LSOverride
|
||||
.idea
|
||||
.vscode
|
||||
package-lock.json
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent.io@gmail.com)
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2018-08-04 01:00:06
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
require('es.shim')
|
||||
const fs = require('iofs')
|
||||
const path = require('path')
|
||||
const chokidar = require('chokidar')
|
||||
const { minify } = require('terser')
|
||||
const uglify = require('uglify-es')
|
||||
const chalk = require('chalk')
|
||||
const config = require('./package.json')
|
||||
const log = console.log
|
||||
const VERSION = config.version
|
||||
const VERSION = '2.0.0'
|
||||
|
||||
const PACK_DIR = path.resolve('./dist')
|
||||
const SOURCE_DIR = path.resolve('./src/')
|
||||
|
@ -58,9 +59,9 @@ export default _Anot
|
|||
function comment({ touch } = {}) {
|
||||
return `/*==================================================
|
||||
* Anot ${touch ? 'touch' : 'normal'} version for future browsers
|
||||
* @authors yutent<yutent.io@gmail.com>
|
||||
* @date ${new Date().format()}
|
||||
* @version v${VERSION}
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2017-03-21 21:05:57
|
||||
* V${VERSION}
|
||||
*
|
||||
==================================================*/
|
||||
`
|
||||
|
@ -114,8 +115,8 @@ function packNoCompress(file) {
|
|||
* 打包带触摸事件的未来版的 anot
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
fs.echo(Buffer.concat([PAD_START, touchVer, PAD_END]), './dist/anot.touch.js')
|
||||
log('%s 打包完成...', chalk.green('anot.touch.js'))
|
||||
fs.echo(Buffer.concat([PAD_START, touchVer, PAD_END]), './dist/anot-touch.js')
|
||||
log('%s 打包完成...', chalk.green('anot-touch.js'))
|
||||
}
|
||||
|
||||
// 打包并压缩
|
||||
|
@ -135,24 +136,22 @@ function packAndCompress() {
|
|||
*/
|
||||
log('正在打包 anot.js...')
|
||||
let normalVerPack = Buffer.concat([PAD_START, normalVer, PAD_END]).toString()
|
||||
|
||||
minify(normalVerPack, { sourceMap: false }).then(res => {
|
||||
fs.echo(comment() + res.code, './dist/anot.js')
|
||||
log(chalk.green('anot.js 打包压缩完成!'))
|
||||
})
|
||||
fs.echo(comment() + uglify.minify(normalVerPack).code, './dist/anot.js')
|
||||
log(chalk.green('anot.js 打包压缩完成!'))
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------
|
||||
* 打包带触摸事件的未来版的 anot
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
log('正在打包 anot.touch.js...')
|
||||
log('正在打包 anot-touch.js...')
|
||||
let touchVerPack = Buffer.concat([PAD_START, touchVer, PAD_END]).toString()
|
||||
|
||||
minify(touchVerPack, { sourceMap: false }).then(res => {
|
||||
fs.echo(comment({ touch: true }) + res.code, './dist/anot.touch.js')
|
||||
log(chalk.green('anot.touch.js 打包压缩完成!'))
|
||||
})
|
||||
fs.echo(
|
||||
comment({ touch: true }) + uglify.minify(touchVerPack).code,
|
||||
'./dist/anot-touch.js'
|
||||
)
|
||||
log(chalk.green('anot-touch.js 打包压缩完成!'))
|
||||
}
|
||||
|
||||
let args = process.argv.slice(2)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "anot",
|
||||
"version": "2.2.4",
|
||||
"version": "2.0.0",
|
||||
"description": "Anot - 迷你mvvm框架",
|
||||
"main": "dist/anot.js",
|
||||
"files": ["dist"],
|
||||
|
@ -14,9 +14,9 @@
|
|||
"devDependencies": {
|
||||
"chalk": "^2.4.1",
|
||||
"chokidar": "^2.0.4",
|
||||
"es.shim": "^2.0.1",
|
||||
"iofs": "^1.5.2",
|
||||
"terser": "^5.0.0"
|
||||
"es.shim": "^1.1.2",
|
||||
"iofs": "^1.1.0",
|
||||
"uglify-es": "^3.3.9"
|
||||
},
|
||||
"repository": "https://github.com/yutent/anot.js.git",
|
||||
"author": "yutent",
|
||||
|
|
|
@ -16,7 +16,7 @@ npm run prod
|
|||
```
|
||||
执行完, 会打包为2个版本, 分别是
|
||||
- anot.js 普通版(需要支持es6 module的现代浏览器)
|
||||
- anot.touch.js 带触摸事件的版本(需要支持es6 module的现代浏览器)
|
||||
- anot-touch.js 带触摸的版本(需要支持es6 module的现代浏览器)
|
||||
|
||||
|
||||
### 文档:
|
||||
|
|
|
@ -9,7 +9,7 @@ var DOC = window.document
|
|||
var head = DOC.head //HEAD元素
|
||||
head.insertAdjacentHTML(
|
||||
'afterbegin',
|
||||
'<anot skip class="anot-hide"><style id="anot-style">.anot-hide{ display: none!important }</style></anot>'
|
||||
'<anot skip class="anot-hide"><style id="anot-style">.anot-hide{ display: none!important } slot{visibility:hidden;}</style></anot>'
|
||||
)
|
||||
var ifGroup = head.firstChild
|
||||
|
||||
|
@ -31,8 +31,6 @@ function createMap() {
|
|||
return Object.create(null)
|
||||
}
|
||||
|
||||
var encode = encodeURIComponent
|
||||
var decode = decodeURIComponent
|
||||
var subscribers = '$' + expose
|
||||
|
||||
var nullObject = {} //作用类似于noop,只用于代码防御,千万不要在它上面添加属性
|
||||
|
|
|
@ -4,7 +4,14 @@ let Anot = function(el) {
|
|||
}
|
||||
|
||||
/*视浏览器情况采用最快的异步回调*/
|
||||
Anot.nextTick = (function() {
|
||||
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
|
||||
|
@ -14,16 +21,21 @@ Anot.nextTick = (function() {
|
|||
queue = queue.slice(n)
|
||||
}
|
||||
|
||||
let node = document.createTextNode('<!-- -->')
|
||||
new MutationObserver(callback).observe(node, { characterData: true })
|
||||
|
||||
let bool = false
|
||||
return function(fn) {
|
||||
queue.push(fn)
|
||||
bool = !bool
|
||||
node.data = bool
|
||||
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的静态方法定义区 *
|
||||
|
@ -85,7 +97,10 @@ Anot.PropsTypes.isBoolean = function() {
|
|||
/*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/
|
||||
Anot.isPlainObject = function(obj) {
|
||||
// 简单的 typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通不过
|
||||
return serialize.call(obj) === '[object Object]' && Object.getPrototypeOf(obj) === oproto
|
||||
return (
|
||||
serialize.call(obj) === '[object Object]' &&
|
||||
Object.getPrototypeOf(obj) === oproto
|
||||
)
|
||||
}
|
||||
|
||||
let VMODELS = (Anot.vmodels = {}) //所有vmodel都储存在这里
|
||||
|
@ -165,7 +180,11 @@ Anot.mix = Anot.fn.mix = function() {
|
|||
if (target === copy) {
|
||||
continue
|
||||
}
|
||||
if (deep && copy && (Anot.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
|
||||
if (
|
||||
deep &&
|
||||
copy &&
|
||||
(Anot.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))
|
||||
) {
|
||||
if (copyIsArray) {
|
||||
copyIsArray = false
|
||||
clone = src && Array.isArray(src) ? src : []
|
||||
|
@ -271,11 +290,11 @@ Anot.mix({
|
|||
t = t.trim()
|
||||
let hook = hooks[t]
|
||||
if (typeof hook === 'object') {
|
||||
t = hook.type || t
|
||||
phase = hook.phase || phase
|
||||
type = hook.type || type
|
||||
phase = hook.phase || !!phase
|
||||
fn = hook.fix ? hook.fix(el, fn) : fn
|
||||
}
|
||||
el.addEventListener(t, fn, !!phase)
|
||||
el.addEventListener(t, fn, phase)
|
||||
})
|
||||
return fn
|
||||
},
|
||||
|
@ -288,10 +307,10 @@ Anot.mix({
|
|||
t = t.trim()
|
||||
let hook = hooks[t]
|
||||
if (typeof hook === 'object') {
|
||||
t = hook.type || t
|
||||
phase = hook.phase || phase
|
||||
type = hook.type || type
|
||||
phase = hook.phase || !!phase
|
||||
}
|
||||
el.removeEventListener(t, fn, !!phase)
|
||||
el.removeEventListener(t, fn, phase)
|
||||
})
|
||||
},
|
||||
/*读写删除元素节点的样式*/
|
||||
|
@ -330,12 +349,13 @@ Anot.mix({
|
|||
each: function(obj, fn) {
|
||||
if (obj) {
|
||||
//排除null, undefined
|
||||
let i = 0
|
||||
if (isArrayLike(obj)) {
|
||||
for (let i = 0, n = obj.length; i < n; i++) {
|
||||
for (let n = obj.length; i < n; i++) {
|
||||
if (fn(i, obj[i]) === false) break
|
||||
}
|
||||
} else {
|
||||
for (let i in obj) {
|
||||
for (i in obj) {
|
||||
if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) {
|
||||
break
|
||||
}
|
||||
|
@ -404,7 +424,7 @@ Anot.mix({
|
|||
|
||||
if ((this.type(val) == 'string' && val.trim() === '') || val === null) {
|
||||
document.cookie =
|
||||
encode(key) +
|
||||
encodeURIComponent(key) +
|
||||
'=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=' +
|
||||
opt.domain +
|
||||
'; path=' +
|
||||
|
@ -428,9 +448,9 @@ Anot.mix({
|
|||
}
|
||||
}
|
||||
document.cookie =
|
||||
encode(key) +
|
||||
encodeURIComponent(key) +
|
||||
'=' +
|
||||
encode(val) +
|
||||
encodeURIComponent(val) +
|
||||
opt.expires +
|
||||
'; domain=' +
|
||||
opt.domain +
|
||||
|
@ -444,11 +464,11 @@ Anot.mix({
|
|||
return document.cookie
|
||||
}
|
||||
return (
|
||||
decode(
|
||||
decodeURIComponent(
|
||||
document.cookie.replace(
|
||||
new RegExp(
|
||||
'(?:(?:^|.*;)\\s*' +
|
||||
encode(key).replace(/[\-\.\+\*]/g, '\\$&') +
|
||||
encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') +
|
||||
'\\s*\\=\\s*([^;]*).*$)|^.*$'
|
||||
),
|
||||
'$1'
|
||||
|
@ -459,12 +479,13 @@ Anot.mix({
|
|||
},
|
||||
//获取url的参数
|
||||
search: function(key) {
|
||||
key += ''
|
||||
let uri = location.search
|
||||
|
||||
if (!uri) {
|
||||
if (!key || !uri) {
|
||||
return null
|
||||
}
|
||||
uri = decode(uri)
|
||||
uri = decodeURIComponent(uri)
|
||||
|
||||
uri = uri.slice(1)
|
||||
uri = uri.split('&')
|
||||
|
@ -485,19 +506,26 @@ Anot.mix({
|
|||
obj[tmp[0]] = tmp[1]
|
||||
}
|
||||
}
|
||||
if (key) {
|
||||
return obj.hasOwnProperty(key) ? obj[key] : null
|
||||
} else {
|
||||
return obj
|
||||
}
|
||||
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 {
|
||||
navigator.clipboard.writeText(txt)
|
||||
DOC.execCommand('copy')
|
||||
} catch (err) {
|
||||
log('复制到粘贴板失败', err)
|
||||
}
|
||||
DOC.body.removeChild(ta)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -21,6 +21,46 @@ Anot.contains = function(root, el) {
|
|||
|
||||
let eventHooks = Anot.eventHooks
|
||||
|
||||
//针对firefox, chrome修正mouseenter, mouseleave(chrome30+)
|
||||
if (!('onmouseenter' in root)) {
|
||||
Anot.each(
|
||||
{
|
||||
mouseenter: 'mouseover',
|
||||
mouseleave: 'mouseout'
|
||||
},
|
||||
function(origType, fixType) {
|
||||
eventHooks[origType] = {
|
||||
type: fixType,
|
||||
fix: function(elem, fn) {
|
||||
return function(e) {
|
||||
let t = e.relatedTarget
|
||||
if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) {
|
||||
delete e.type
|
||||
e.type = origType
|
||||
return fn.call(elem, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//针对IE9+, w3c修正animationend
|
||||
Anot.each(
|
||||
{
|
||||
AnimationEvent: 'animationend',
|
||||
WebKitAnimationEvent: 'webkitAnimationEnd'
|
||||
},
|
||||
function(construct, fixType) {
|
||||
if (window[construct] && !eventHooks.animationend) {
|
||||
eventHooks.animationend = {
|
||||
type: fixType
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (DOC.onmousewheel === void 0) {
|
||||
/* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120
|
||||
firefox DOMMouseScroll detail 下3 上-3
|
||||
|
|
|
@ -264,8 +264,8 @@ function observeObject(source, options) {
|
|||
return (old = value.get.call(this))
|
||||
},
|
||||
set: function(x) {
|
||||
var older = old
|
||||
var newer
|
||||
var older = old,
|
||||
newer
|
||||
value.set.call(this, x)
|
||||
newer = this[key]
|
||||
if (this.$fire && newer !== older) {
|
||||
|
|
|
@ -50,13 +50,13 @@ function executeBindings(bindings, vmodels) {
|
|||
}
|
||||
|
||||
var roneTime = /^\s*::/
|
||||
var rmsAttr = /^:(\w+)-?(.*)|@(.*)/
|
||||
var rmsAttr = /:(\w+)-?(.*)|@(.*)/
|
||||
|
||||
var events = oneObject(
|
||||
'animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit'
|
||||
)
|
||||
var obsoleteAttrs = oneObject(
|
||||
'value,title,alt,checked,selected,disabled,readonly,loading,enabled,href,src'
|
||||
'value,title,alt,checked,selected,disabled,readonly,enabled,href,src'
|
||||
)
|
||||
function bindingSorter(a, b) {
|
||||
return a.priority - b.priority
|
||||
|
@ -85,12 +85,8 @@ function scanAttr(elem, vmodels, match) {
|
|||
var param = match[2] || ''
|
||||
var eparam = match[3] || '' // 事件绑定的简写
|
||||
var value = attr.value
|
||||
if (obsoleteAttrs[type]) {
|
||||
param = type
|
||||
type = 'attr'
|
||||
}
|
||||
if (eparam) {
|
||||
param = eparam
|
||||
if (events[type] || events[eparam]) {
|
||||
param = type || eparam
|
||||
type = 'on'
|
||||
}
|
||||
if (directives[type]) {
|
||||
|
@ -372,8 +368,6 @@ function scanText(textNode, vmodels, index) {
|
|||
anotFragment.appendChild(node)
|
||||
}
|
||||
textNode.parentNode.replaceChild(anotFragment, textNode)
|
||||
if (bindings.length) {
|
||||
executeBindings(bindings, vmodels)
|
||||
}
|
||||
if (bindings.length) executeBindings(bindings, vmodels)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,7 @@ var attrDir = Anot.directive('attr', {
|
|||
},
|
||||
update: function(val) {
|
||||
var elem = this.element
|
||||
var obj = Object.create(null)
|
||||
var isSVG = rsvg.test(elem)
|
||||
var obj = {}
|
||||
|
||||
val = toJson(val)
|
||||
|
||||
|
@ -84,47 +83,36 @@ var attrDir = Anot.directive('attr', {
|
|||
elem.style.cssText = obj[i]
|
||||
continue
|
||||
}
|
||||
|
||||
if (i.slice(0, 6) === 'xlink:') {
|
||||
var k = i
|
||||
i = i.slice(6)
|
||||
obj[i] = obj[k]
|
||||
delete obj[k]
|
||||
}
|
||||
// 修正这些值的显示
|
||||
if (obj[i] === false || obj[i] === null || obj[i] === undefined) {
|
||||
obj[i] = ''
|
||||
}
|
||||
|
||||
if (
|
||||
typeof elem[i] === 'boolean' ||
|
||||
typeof elem[boolMap[i]] === 'boolean'
|
||||
) {
|
||||
var k = i
|
||||
if (boolMap[i] && k !== boolMap[i]) {
|
||||
k = boolMap[i]
|
||||
}
|
||||
//布尔属性必须使用el.xxx = true|false方式设值
|
||||
obj[i] = !!obj[i]
|
||||
elem[k] = obj[i]
|
||||
|
||||
if (!obj[i]) {
|
||||
elem.removeAttribute(k)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
//SVG只能使用setAttribute(xxx, yyy), HTML的固有属性必须elem.xxx = yyy
|
||||
var isInnate = isSVG ? false : i in elem.cloneNode(false)
|
||||
if (isInnate) {
|
||||
if (i === 'href' || i === 'src') {
|
||||
elem[i] = obj[i]
|
||||
} else {
|
||||
if (typeof obj[i] === 'object') {
|
||||
obj[i] = Date.isDate(obj[i])
|
||||
? obj[i].toISOString()
|
||||
: JSON.stringify(obj[i])
|
||||
if (obj[i] === false || obj[i] === null || obj[i] === undefined) {
|
||||
obj[i] = ''
|
||||
}
|
||||
|
||||
if (typeof elem[boolMap[i]] === 'boolean') {
|
||||
//布尔属性必须使用el.xxx = true|false方式设值
|
||||
obj[i] = !!obj[i]
|
||||
elem[boolMap[i]] = obj[i]
|
||||
|
||||
if (!obj[i]) {
|
||||
elem.removeAttribute(boolMap[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
//SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy
|
||||
var isInnate = rsvg.test(elem) ? false : i in elem.cloneNode(false)
|
||||
if (isInnate) {
|
||||
elem[i] = obj[i]
|
||||
} else {
|
||||
if (typeof obj[i] === 'object') {
|
||||
obj[i] = Date.isDate(obj[i])
|
||||
? obj[i].toISOString()
|
||||
: JSON.stringify(obj[i])
|
||||
}
|
||||
elem.setAttribute(i, obj[i])
|
||||
}
|
||||
elem.setAttribute(i, obj[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,26 +20,6 @@ function nodesToFrag(nodes) {
|
|||
}
|
||||
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) {
|
||||
|
@ -161,17 +141,27 @@ Anot.directive('include', {
|
|||
scanTemplate(templatePool[val])
|
||||
})
|
||||
} else {
|
||||
_fetch(val)
|
||||
fetch(val, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
if (res.status >= 200 && res.status < 300) {
|
||||
return res.text()
|
||||
} else {
|
||||
return Promise.reject(
|
||||
`获取网络资源出错, ${res.status} (${res.statusText})`
|
||||
)
|
||||
}
|
||||
})
|
||||
.then(text => {
|
||||
templatePool[val] = text
|
||||
scanTemplate(text)
|
||||
})
|
||||
.catch(err => {
|
||||
log(
|
||||
':include load [' + val + '] error\n%c%s',
|
||||
'color:#f30',
|
||||
`获取网络资源出错, ${err.status} (${err.statusText})`
|
||||
)
|
||||
log(':include load [' + val + '] error\n%c%s', 'color:#f30', err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue