mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
6.4 KiB
JavaScript
294 lines
6.4 KiB
JavaScript
|
|
|
|
function CamelToKebabCase(str) {
|
|
// 首先将字符串的第一个字符转换为小写,避免在首字符前加上'-'
|
|
if (str.length === 0) return '';
|
|
let firstChar = str.charAt(0).toLowerCase();
|
|
|
|
// 对剩余部分应用原逻辑:找到每个大写字母,并替换为连字符加上该字母的小写形式
|
|
let rest = str.slice(1).replace(/([A-Z])/g, function(match, p1) {
|
|
return '-' + p1.toLowerCase();
|
|
});
|
|
|
|
return firstChar + rest;
|
|
}
|
|
|
|
const outerClickList = []
|
|
const globalClick = document.addEventListener('click', (event) => {
|
|
outerClickList.forEach((item) => {
|
|
if (item?.dom instanceof Element && typeof item?.callback === 'function') {
|
|
if (!item.dom.contains(event.target)) {
|
|
item.callback(event)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
const AddClicker = (dom, typ, callback) => {
|
|
if (typ === 'outer') {
|
|
let idx = outerClickList.length
|
|
outerClickList.push({ dom, callback })
|
|
return () => {
|
|
outerClickList[idx] = null
|
|
}
|
|
}
|
|
}
|
|
|
|
const EventsList = [
|
|
// 窗口和框架事件
|
|
'load',
|
|
'unload',
|
|
'beforeunload',
|
|
'resize',
|
|
'scroll',
|
|
|
|
// 表单事件
|
|
'submit',
|
|
'reset',
|
|
'input',
|
|
'change',
|
|
'focus',
|
|
'blur',
|
|
|
|
// 键盘事件
|
|
'keydown',
|
|
'keypress',
|
|
'keyup',
|
|
|
|
// 鼠标事件
|
|
'click',
|
|
'dblclick',
|
|
'contextmenu',
|
|
'mousedown',
|
|
'mouseup',
|
|
'mousemove',
|
|
'mouseover',
|
|
'mouseout',
|
|
'mouseenter',
|
|
'mouseleave',
|
|
|
|
// 触摸事件
|
|
'touchstart',
|
|
'touchmove',
|
|
'touchend',
|
|
'touchcancel',
|
|
|
|
// 拖拽事件
|
|
'drag',
|
|
'dragstart',
|
|
'dragend',
|
|
'dragover',
|
|
'dragenter',
|
|
'dragleave',
|
|
'drop',
|
|
|
|
// 剪贴板事件
|
|
'copy',
|
|
'cut',
|
|
'paste',
|
|
|
|
// 动画事件
|
|
'animationstart',
|
|
'animationend',
|
|
'animationiteration',
|
|
|
|
// 过渡事件
|
|
'transitionend',
|
|
|
|
// 文件操作事件
|
|
'abort',
|
|
'error',
|
|
'loadstart',
|
|
'progress',
|
|
|
|
// 音视频事件
|
|
'play',
|
|
'pause',
|
|
'ended',
|
|
'volumechange',
|
|
'timeupdate',
|
|
'loadeddata',
|
|
'waiting',
|
|
'playing',
|
|
|
|
// 网络状态事件
|
|
'online',
|
|
'offline',
|
|
|
|
// 存储事件
|
|
'storage',
|
|
|
|
// 页面可见性事件
|
|
'visibilitychange'
|
|
];
|
|
|
|
function BindInputDomValue(dom, data, key, watch) {
|
|
const element = typeof dom === 'string' ? document.querySelector(dom) : dom;
|
|
|
|
if (!element) {
|
|
console.error('DOM元素未找到');
|
|
return;
|
|
}
|
|
// 根据元素类型进行双向绑定
|
|
const elementType = element.type || element.tagName.toLowerCase();
|
|
switch (elementType) {
|
|
// 文本输入类
|
|
case 'text':
|
|
case 'password':
|
|
case 'email':
|
|
case 'tel':
|
|
case 'url':
|
|
case 'search':
|
|
case 'number':
|
|
case 'range':
|
|
case 'color':
|
|
case 'date':
|
|
case 'time':
|
|
case 'datetime-local':
|
|
case 'month':
|
|
case 'week':
|
|
case 'hidden':
|
|
case 'textarea':
|
|
watch(() => data[key], (value) => {
|
|
if (value === undefined) {
|
|
element.value = ''
|
|
} else {
|
|
element.value = value
|
|
}
|
|
})
|
|
element.addEventListener('input', function() {
|
|
data[key] = this.value;
|
|
});
|
|
break;
|
|
case 'checkbox':
|
|
watch(function() {
|
|
element.checked = !!data[key];
|
|
});
|
|
element.addEventListener('change', function() {
|
|
data[key] = this.checked;
|
|
console.log(data, data[key])
|
|
});
|
|
break;
|
|
// 单选框
|
|
case 'radio':
|
|
// 初始化
|
|
watch(() => {
|
|
element.checked = element.value === data[key];
|
|
})
|
|
element.addEventListener('change', function() {
|
|
if (this.checked) {
|
|
data[key] = this.value;
|
|
}
|
|
});
|
|
break;
|
|
|
|
// 下拉选择框
|
|
case 'select-one':
|
|
case 'select-multiple':
|
|
watch(() => {
|
|
let newValue = data[key]
|
|
if (element.multiple) {
|
|
const values = Array.isArray(newValue) ? newValue : [];
|
|
for (let i = 0; i < element.options.length; i++) {
|
|
element.options[i].selected = values.includes(element.options[i].value);
|
|
}
|
|
} else {
|
|
element.value = newValue || '';
|
|
}
|
|
});
|
|
// 监听变化
|
|
element.addEventListener('change', function() {
|
|
if (this.multiple) {
|
|
// 多选
|
|
const selectedValues = [];
|
|
for (let i = 0; i < this.options.length; i++) {
|
|
if (this.options[i].selected) {
|
|
selectedValues.push(this.options[i].value);
|
|
}
|
|
}
|
|
data[key] = selectedValues;
|
|
} else {
|
|
// 单选
|
|
data[key] = this.value;
|
|
}
|
|
});
|
|
break;
|
|
|
|
default:
|
|
console.warn(`${elementType} not support v!bind only for input element`, element);
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
function SetAttr(dom, key, value) {
|
|
// 属性名映射表
|
|
const propertyMap = {
|
|
'htmlfor': 'htmlFor',
|
|
'readonly': 'readOnly',
|
|
'maxlength': 'maxLength',
|
|
'minlength': 'minLength',
|
|
'cellspacing': 'cellSpacing',
|
|
'cellpadding': 'cellPadding',
|
|
'rowspan': 'rowSpan',
|
|
'colspan': 'colSpan',
|
|
'tabindex': 'tabIndex',
|
|
'usemap': 'useMap',
|
|
'frameborder': 'frameBorder',
|
|
'contenteditable': 'contentEditable',
|
|
'spellcheck': 'spellcheck',
|
|
'innerhtml': 'innerHTML',
|
|
'innertext': 'innerText',
|
|
'autocapitalize': 'autocapitalize',
|
|
};
|
|
|
|
// 需要使用 DOM 属性设置的属性
|
|
const domProperties = new Set([
|
|
'innerHTML', 'innerText', 'outerHTML', 'textContent',
|
|
'value', 'checked', 'selected', 'disabled', 'readOnly',
|
|
'maxLength', 'minLength', 'htmlFor',
|
|
'tabIndex', 'scrollTop', 'scrollLeft', 'scrollWidth', 'scrollHeight',
|
|
'clientWidth', 'clientHeight', 'offsetWidth', 'offsetHeight',
|
|
'style', 'dataset'
|
|
]);
|
|
|
|
// 布尔属性
|
|
const booleanAttributes = new Set([
|
|
'checked', 'selected', 'disabled', 'readonly', 'required',
|
|
'hidden', 'autofocus', 'multiple', 'novalidate'
|
|
]);
|
|
|
|
// 转换属性名
|
|
const lowerKey = key.toLowerCase();
|
|
const mappedKey = propertyMap[lowerKey] || key;
|
|
|
|
|
|
|
|
// 设置属性的策略:
|
|
if (domProperties.has(mappedKey)) {
|
|
// DOM 属性
|
|
if (value === undefined) {
|
|
dom[mappedKey] = ''
|
|
} else {
|
|
dom[mappedKey] = value;
|
|
}
|
|
} else if (booleanAttributes.has(lowerKey)) {
|
|
// 布尔属性
|
|
if (value) {
|
|
dom.setAttribute(lowerKey, '');
|
|
} else {
|
|
dom.removeAttribute(lowerKey);
|
|
}
|
|
} else {
|
|
// 其他属性使用 setAttribute
|
|
if (value === undefined) {
|
|
dom.removeAttribute(key);
|
|
} else {
|
|
dom.setAttribute(key, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
export default { CamelToKebabCase, EventsList, BindInputDomValue, SetAttr, AddClicker }
|
|
|