wkit/src/utils.js

242 lines
5.1 KiB
JavaScript

/**
* {常用方法库}
* @author yutent<yutent.io@gmail.com>
* @date 2023/03/07 22:11:30
*/
export function noop() {}
export function $(selector, container, multi) {
let fn = multi ? 'querySelectorAll' : 'querySelector'
if (container) {
return container[fn](selector)
}
return document.body[fn](selector)
}
export function $$(selector, container) {
return $(selector, container, true)
}
export const nextTick = (function () {
let queue = []
let node = document.createTextNode('<!-- -->')
let bool = false
function callback() {
while (queue.length > 0) {
let fn = queue.shift()
try {
fn()
} catch (err) {
console.error(err)
}
}
}
new MutationObserver(callback).observe(node, { characterData: true })
return function (fn) {
queue.push(fn)
bool = !bool
node.data = bool
}
})()
export function range(...args) {
let start = 0,
end = 0,
step = 1,
out = []
switch (args.length) {
case 1:
end = args[0]
break
case 2:
case 3:
;[start, end, step = 1] = args
step = Math.abs(step) || 1
break
}
if (start > end) {
;[start, end] = [end, start]
}
for (let i = start; i < end; i += step) {
out.push(i)
}
return out
}
//驼峰转换为连字符线风格
export function hyphen(target) {
return target.replace(/([a-z\d])([A-Z]+)/g, '$1-$2').toLowerCase()
}
//连字符转换为驼峰风格
export function camelize(target) {
//提前判断,提高效率
if (target.indexOf('-') < 0) {
return target
}
return target.replace(/\-([a-z])/g, (m, s) => s.toUpperCase())
}
//取得距离页面左上角的坐标
export function offset(node) {
try {
let rect = node.getBoundingClientRect()
if (rect.width || rect.height || node.getClientRects().length) {
let doc = node.ownerDocument
let root = doc.documentElement
let win = doc.defaultView
return {
top: rect.top + win.pageYOffset - root.clientTop,
left: rect.left + win.pageXOffset - root.clientLeft
}
}
} catch (e) {
return {
left: 0,
top: 0
}
}
}
/**
* 事件绑定
*/
export function bind(dom, type = '', selector, fn, phase = false) {
let events = type.split(',')
let callback
let isWc = dom && dom.host === dom
let host = isWc ? dom : null
if (!dom || !type) {
return console.error(
"Argument Error: function bind's arg 1 must be a document obejct"
)
}
if (typeof selector === 'function') {
phase = fn || false
fn = selector
selector = null
} else {
if (typeof selector !== 'string') {
selector = null
}
fn = fn || noop
}
if (isWc === false) {
let node = dom
while (node && node !== document.body && node !== document) {
if (node.ownHost) {
isWc = true
host = node.ownHost
break
}
node = node.parentNode
}
}
if (selector) {
callback = function (ev) {
let agents = $(selector, dom)
let elem = ev.target
if (agents) {
while (true) {
if (elem === dom) {
break
}
if (agents.contains(elem)) {
fn(ev)
break
} else {
elem = elem.parentNode
}
}
}
}
} else {
callback = fn
}
events.forEach(function (t) {
t = t.trim()
if (isWc) {
host.$events[t] ??= []
let _list = host.$events[t]
if (_list.length) {
let idx = _list.findIndex(
it =>
it.el === dom && it.listener === callback && it.options === phase
)
if (idx > -1) {
let item = _list[idx]
_list.splice(idx, 1)
dom.removeEventListener(t, item.listener, item.options)
}
}
_list.push({ el: dom, listener: callback, options: phase })
}
dom.addEventListener(t, callback, phase)
})
return callback
}
/**
* 解除事件绑定
*/
export function unbind(dom, type = '', fn = noop, phase = false) {
let events = type.split(',')
events.forEach(function (t) {
dom.removeEventListener(t.trim(), fn, phase)
})
}
// 指定节点外点击(最高不能超过body层)
export function outsideClick(dom, fn = noop) {
return bind(document, 'mousedown', ev => {
let path = ev.composedPath ? ev.composedPath() : ev.path
if (path) {
while (path.length > 3) {
if (path.shift() === dom) {
return
}
}
} else {
let target = ev.explicitOriginalTarget || ev.target
if (
dom === target ||
dom.contains(target) ||
(dom.root && dom.root.contains(target))
) {
return
}
}
fn(ev)
})
}
export function clearOutsideClick(fn = noop) {
unbind(document, 'mousedown', fn)
}
/**
* @param el <DOM> 节点
* @param name <String> 自定义的事件名
* @param data <Object> 要合并进event对象的参数
* @param stop <Boolean> 是否禁止事件冒泡
*/
export function fire(el, name = 'click', data = {}, stop) {
let ev = new Event(name, { bubbles: !stop, cancelable: true })
Object.assign(ev, data)
el.dispatchEvent(ev)
}
一个简单易用、功能完善的用于开发`web components`的轻量级开发库。模板解析基于`lit-html`二次开发
JavaScript 97%
HTML 3%