UNPKG

@vxe-ui/core

Version:
921 lines (893 loc) 25.1 kB
import { h, reactive, computed, inject, provide, createCommentVNode } from 'vue'; import XEUtils from 'xe-utils'; import DomZIndex from 'dom-zindex'; const coreVersion = "4.4.19"; const VxeCore = { coreVersion, uiVersion: '', tableVersion: '', designVersion: '', ganttVersion: '' }; const globalConfigStore = { size: '', version: 1, zIndex: 999, resizeInterval: 500 }; const themeConfigStore = { theme: '' }; function setTheme(name) { const theme = !name || name === 'default' ? 'light' : name; themeConfigStore.theme = theme; if (typeof document !== 'undefined') { const documentElement = document.documentElement; if (documentElement) { documentElement.setAttribute('data-vxe-ui-theme', theme); } } return VxeCore; } function getTheme() { return themeConfigStore.theme; } /** * 全局参数设置 */ function setConfig(options) { if (options) { if (options.zIndex) { DomZIndex.setCurrent(options.zIndex); } if (options.theme) { setTheme(options.theme); } XEUtils.merge(globalConfigStore, options); } return VxeCore; } /** * 获取全局参数 */ function getConfig(key, defaultValue) { return arguments.length ? XEUtils.get(globalConfigStore, key, defaultValue) : globalConfigStore; } const globalStore = {}; const iconConfigStore = {}; function getSlotVNs(vns) { if (XEUtils.isArray(vns)) { return vns; } return vns ? [vns] : []; } function setIcon(options) { if (options) { Object.assign(iconConfigStore, options); } return VxeCore; } function getIcon(key) { return arguments.length ? XEUtils.get(iconConfigStore, key) : iconConfigStore; } function renderGlobalIcon(name) { const icon = getIcon(name); return renderCustomIcon(icon, name); } function renderCustomIcon(icon, name) { if (XEUtils.isFunction(icon)) { return h('span', {}, getSlotVNs(icon({ name }))); } return h('i', { class: icon }); } const GLOBAL_EVENT_KEYS = { F2: 'F2', F10: 'F10', TAB: 'Tab', ESCAPE: 'Escape', ENTER: 'Enter', DELETE: 'Delete', BACKSPACE: 'Backspace', SPACEBAR: ' ', CONTEXT_MENU: 'ContextMenu', ARROW_UP: 'ArrowUp', ARROW_DOWN: 'ArrowDown', ARROW_LEFT: 'ArrowLeft', ARROW_RIGHT: 'ArrowRight', PAGE_UP: 'PageUp', PAGE_DOWN: 'PageDown', HOME: 'Home', END: 'End', A: 'A', X: 'X', C: 'C', V: 'V', D: 'D', F: 'F', H: 'H', M: 'M', Y: 'Y', Z: 'Z', R: 'R', P: 'P' }; const browse = XEUtils.browse(); const convertEventKeys = { ' ': 'Spacebar', Apps: GLOBAL_EVENT_KEYS.CONTEXT_MENU, Del: GLOBAL_EVENT_KEYS.DELETE, Up: GLOBAL_EVENT_KEYS.ARROW_UP, Down: GLOBAL_EVENT_KEYS.ARROW_DOWN, Left: GLOBAL_EVENT_KEYS.ARROW_LEFT, Right: GLOBAL_EVENT_KEYS.ARROW_RIGHT }; // 监听全局事件 const wheelName = browse.firefox ? 'DOMMouseScroll' : 'mousewheel'; const eventStore$1 = []; function triggerEvent(evnt) { const isWheel = evnt.type === wheelName; eventStore$1.forEach(({ type, cb }) => { // 如果被取消冒泡,不再执行 if (!evnt.cancelBubble) { if (type === evnt.type || (isWheel && type === 'mousewheel')) { cb(evnt); } } }); } class VxeComponentEvent { constructor(evnt, params1, params2) { Object.defineProperty(this, "$event", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "type", { enumerable: true, configurable: true, writable: true, value: '' }); Object.defineProperty(this, "key", { enumerable: true, configurable: true, writable: true, value: '' }); Object.defineProperty(this, "code", { enumerable: true, configurable: true, writable: true, value: '' }); this.$event = evnt; if (evnt) { if (evnt.type) { this.type = evnt.type; } if (evnt.key) { this.key = evnt.key; } if (evnt.code) { this.code = evnt.code; } } Object.assign(this, params1); XEUtils.objectEach(params2, (val, key) => { if (XEUtils.isFunction(val)) { let rest = null; let isRun = false; Object.defineProperty(this, key, { get() { if (!isRun) { isRun = true; rest = val(); } return rest; } }); } else { this[key] = val; } }); } stopPropagation() { const evnt = this.$event; if (evnt) { evnt.stopPropagation(); } } preventDefault() { const evnt = this.$event; if (evnt) { evnt.preventDefault(); } } } const createEvent = (evnt, params1, params2) => { if (evnt instanceof VxeComponentEvent) { evnt = evnt.$event; } return new VxeComponentEvent(evnt, params1, params2); }; const globalEvents = { on(comp, type, cb) { eventStore$1.push({ comp, type, cb }); }, off(comp, type) { XEUtils.remove(eventStore$1, item => item.comp === comp && item.type === type); }, hasKey(evnt, targetKey) { if (!targetKey) { return false; } const { key } = evnt; targetKey = targetKey.toLowerCase(); return key ? (targetKey === key.toLowerCase() || !!(convertEventKeys[key] && convertEventKeys[key].toLowerCase() === targetKey)) : false; } }; if (browse.isDoc) { if (!browse.msie) { window.addEventListener('copy', triggerEvent, false); window.addEventListener('cut', triggerEvent, false); window.addEventListener('paste', triggerEvent, false); } document.addEventListener('scroll', triggerEvent, true); document.addEventListener('keydown', triggerEvent, false); document.addEventListener('contextmenu', triggerEvent, false); window.addEventListener('mousedown', triggerEvent, false); window.addEventListener('click', triggerEvent, false); window.addEventListener('blur', triggerEvent, false); window.addEventListener('resize', triggerEvent, false); window.addEventListener(wheelName, XEUtils.throttle(triggerEvent, 100, { leading: true, trailing: false }), { passive: true, capture: false }); } /** * 监听 resize 事件 * 如果项目中已使用了 resize-observer-polyfill,那么只需要将方法定义全局,该组件就会自动使用 */ let resizeTimeout; /* eslint-disable no-use-before-define */ const eventStore = []; const defaultInterval = 500; function eventHandle() { if (eventStore.length) { eventStore.forEach((item) => { item.tarList.forEach((observer) => { const { target, width, heighe } = observer; const clientWidth = target.clientWidth; const clientHeight = target.clientHeight; const rWidth = clientWidth && width !== clientWidth; const rHeight = clientHeight && heighe !== clientHeight; if (rWidth || rHeight) { observer.width = clientWidth; observer.heighe = clientHeight; setTimeout(item.callback); } }); }); /* eslint-disable @typescript-eslint/no-use-before-define */ eventListener(); } } function eventListener() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(eventHandle, globalConfigStore.resizeInterval || defaultInterval); } class XEResizeObserver { constructor(callback) { Object.defineProperty(this, "tarList", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "callback", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.callback = callback; } observe(target) { if (target) { const { tarList } = this; if (!tarList.some(observer => observer.target === target)) { tarList.push({ target, width: target.clientWidth, heighe: target.clientHeight }); } if (!eventStore.length) { eventListener(); } if (!eventStore.some((item) => item === this)) { eventStore.push(this); } } } unobserve(target) { XEUtils.remove(eventStore, item => item.tarList.some(observer => observer.target === target)); } disconnect() { XEUtils.remove(eventStore, item => item === this); } } const globalResize = { create(callback) { if (window.ResizeObserver) { return new window.ResizeObserver(callback); } return new XEResizeObserver(callback); } }; const i18nConfigStore = reactive({ language: '', langMaps: {} }); let checkInstall = false; let cacheMaps = {}; function getDefaultExport(mod) { if (mod && mod.__esModule) { return mod.default; } return mod; } function getI18n(key, args) { const { langMaps, language } = i18nConfigStore; const { i18n } = globalConfigStore; if (i18n) { return `${i18n(key, args) || ''}`; } if (!checkInstall) { if (!langMaps[language]) { console.error(`[vxe core] 语言包未安装。Language not installed. https://${VxeCore.uiVersion ? 'vxeui.com' : 'vxetable.cn'}/#/start/i18n`); } checkInstall = true; } if (!args && cacheMaps[key]) { return cacheMaps[key]; } const i18nLabel = XEUtils.toFormatString(XEUtils.get(langMaps[language], key, key), args); if (!args) { cacheMaps[key] = i18nLabel; } return i18nLabel; } function setLanguage(locale) { const { language } = i18nConfigStore; const targetlang = locale || 'zh-CN'; if (language !== targetlang) { i18nConfigStore.language = targetlang; cacheMaps = {}; } return VxeCore; } function setI18n(locale, data) { i18nConfigStore.langMaps[locale] = Object.assign({}, getDefaultExport(data)); return VxeCore; } function hasLanguage(language) { const { langMaps } = i18nConfigStore; return !!langMaps[language]; } function getLanguage() { const { language } = i18nConfigStore; return language; } function createLog(type, name) { return function (key, args) { const msg = `[vxe ${name || ''}] ${getI18n(key, args)}`; console[type](msg); return msg; }; } const version = "4.4.19"; const log = { create: createLog, warn: createLog('warn', `v${version}`), err: createLog('error', `v${version}`) }; /** * 内置的组件渲染 */ const renderMap = {}; /** * 全局渲染器 */ const renderer = { mixin(opts) { XEUtils.each(opts, (options, name) => renderer.add(name, options)); return renderer; }, get(name) { return renderMap[name] || null; }, add(name, options) { if (name && options) { const renders = renderMap[name]; if (renders) { // 检测是否覆盖 XEUtils.each(options, (val, key) => { if (!XEUtils.eqNull(renders[key]) && renders[key] !== val) { log.warn('vxe.error.coverProp', [`Renderer.${name}`, key]); } }); Object.assign(renders, options); } else { renderMap[name] = options; } } return renderer; }, forEach(callback) { XEUtils.objectEach(renderMap, callback); return renderer; }, delete(name) { delete renderMap[name]; return renderer; } }; /** * 创建数据仓库 */ class Store { constructor() { Object.defineProperty(this, "store", { enumerable: true, configurable: true, writable: true, value: {} }); } mixin(options) { XEUtils.each(options, (item, key) => { this.add(key, item); }); return this; } has(name) { return !!this.get(name); } get(name) { return this.store[name]; } add(name, options) { const conf = this.store[name]; // 检测是否覆盖 const confKeys = XEUtils.keys(conf); XEUtils.each(options, (item, key) => { if (confKeys.includes(key)) { log.warn('vxe.error.coverProp', [name, key]); } }); this.store[name] = conf ? XEUtils.merge(conf, options) : options; return this; } delete(name) { delete this.store[name]; } forEach(callback) { XEUtils.objectEach(this.store, callback); } } const validators = new Store(); Object.assign(validators, { _name: 'Validators' }); class VXEMenusStore { constructor() { Object.defineProperty(this, "store", { enumerable: true, configurable: true, writable: true, value: {} }); } mixin(options) { XEUtils.each(options, (item, key) => { this.add(key, item); }); return this; } has(name) { return !!this.get(name); } get(name) { return this.store[name]; } add(name, render) { const conf = this.store[name]; // 兼容 if (XEUtils.isFunction(render)) { log.warn('vxe.error.delProp', ['menus -> callback', 'menuMethod']); render = { menuMethod: render }; } // 检测是否覆盖 const confKeys = XEUtils.keys(conf); XEUtils.each(render, (item, key) => { if (confKeys.includes(key)) { log.warn('vxe.error.coverProp', [name, key]); } }); this.store[name] = conf ? XEUtils.merge(conf, render) : render; return this; } delete(name) { delete this.store[name]; } forEach(callback) { XEUtils.objectEach(this.store, callback); } } const menus = new VXEMenusStore(); Object.assign(menus, { _name: 'Menus' }); class VXEFormatsStore { constructor() { Object.defineProperty(this, "store", { enumerable: true, configurable: true, writable: true, value: {} }); } mixin(options) { XEUtils.each(options, (item, key) => { this.add(key, item); }); return this; } has(name) { return !!this.get(name); } get(name) { return this.store[name]; } add(name, render) { const conf = this.store[name]; // 兼容 if (XEUtils.isFunction(render)) { log.warn('vxe.error.delProp', ['formats -> callback', 'cellFormatMethod']); render = { cellFormatMethod: render }; } // 检测是否覆盖 const confKeys = XEUtils.keys(conf); XEUtils.each(render, (item, key) => { if (confKeys.includes(key)) { log.warn('vxe.error.coverProp', [name, key]); } }); this.store[name] = conf ? XEUtils.merge(conf, render) : render; return this; } delete(name) { delete this.store[name]; } forEach(callback) { XEUtils.objectEach(this.store, callback); } } const formats = new VXEFormatsStore(); Object.assign(formats, { _name: 'Formats' }); class VXECommandsStore { constructor() { Object.defineProperty(this, "store", { enumerable: true, configurable: true, writable: true, value: {} }); } mixin(options) { XEUtils.each(options, (item, key) => { this.add(key, item); }); return this; } has(name) { return !!this.get(name); } get(name) { return this.store[name]; } add(name, render) { const conf = this.store[name]; // 兼容 if (XEUtils.isFunction(render)) { log.warn('vxe.error.delProp', ['commands -> callback', 'commandMethod']); render = { commandMethod: render }; } // 检测是否覆盖 const confKeys = XEUtils.keys(conf); XEUtils.each(render, (item, key) => { if (confKeys.includes(key)) { log.warn('vxe.error.coverProp', [name, key]); } }); this.store[name] = conf ? XEUtils.merge(conf, render) : render; return this; } delete(name) { delete this.store[name]; } forEach(callback) { XEUtils.objectEach(this.store, callback); } } const commands = new VXECommandsStore(); Object.assign(commands, { _name: 'Commands' }); const storeMap = {}; const interceptor = { mixin(options) { XEUtils.each(options, (render, type) => { interceptor.add(type, render); }); return interceptor; }, get(type) { if (type) { return storeMap[type] || []; } return []; }, add(type, render) { // 兼容 if (XEUtils.isFunction(render)) { // log.warn('vxe.error.delProp', ['interceptor -> callback', 'tableInterceptorMethod']) render = { tableInterceptorMethod: render }; } const callback = render.tableInterceptorMethod; if (callback) { let eList = storeMap[type]; if (!eList) { eList = storeMap[type] = []; } // 检测重复 if (eList.indexOf(callback) > -1) { log.warn('vxe.error.coverProp', ['Interceptor', type]); } eList.push(callback); } return interceptor; }, delete(type, render) { const eList = storeMap[type]; if (eList) { // 兼容 if (XEUtils.isFunction(render)) { render = { tableInterceptorMethod: render }; } const callback = render ? render.tableInterceptorMethod : null; if (callback) { XEUtils.remove(eList, fn => fn === callback); } else { delete storeMap[type]; } } } }; let copyElem; const clipStore = { text: '', html: '' }; function handleText(text) { if (!copyElem) { copyElem = document.createElement('textarea'); copyElem.id = '$VxeCopy'; const styles = copyElem.style; styles.width = '48px'; styles.height = '24px'; styles.position = 'fixed'; styles.zIndex = '0'; styles.left = '-500px'; styles.top = '-500px'; document.body.appendChild(copyElem); } copyElem.value = text; } const clipboard = { getStore() { return clipStore; }, setStore(data) { Object.assign(clipStore, data || {}); }, /** * 复制内容到剪贴板 * * @param {String} content Text 内容 */ copy(content) { let result = false; try { const text = XEUtils.toValueString(content); handleText(text); copyElem.select(); copyElem.setSelectionRange(0, copyElem.value.length); result = document.execCommand('copy'); copyElem.blur(); clipStore.text = text; clipStore.html = ''; } catch (e) { } return result; }, getText() { return clipStore.text || ''; } }; function handleCheckInfo(permissionCode, permissionMethod) { let checkVisible = true; let checkDisabled = false; const checkMethod = permissionMethod || globalConfigStore.permissionMethod; if (permissionCode && checkMethod) { checkVisible = false; checkDisabled = true; let vDone = false; let dDone = false; // 或 使用 | 隔开:任意一个为可视,则可视;任意一个禁用,则禁用 const codeList = String(permissionCode).split('|'); for (let i = 0; i < codeList.length; i++) { const code = codeList[i]; let visible = true; let disabled = false; const rest = checkMethod({ code }); if (XEUtils.isBoolean(rest)) { visible = rest; } else if (rest) { visible = !!rest.visible; disabled = !!rest.disabled; } if (!disabled && !dDone) { dDone = true; checkDisabled = disabled; } if (visible && !vDone) { vDone = true; checkVisible = visible; } if (vDone && dDone) { break; } } } const info = { code: permissionCode, visible: checkVisible, disabled: checkDisabled }; return info; } const permission = { getCheckInfo(code) { return handleCheckInfo(code); }, checkVisible(code) { const permissionInfo = handleCheckInfo(code); return permissionInfo.visible; }, checkDisable(code) { const permissionInfo = handleCheckInfo(code); return permissionInfo.disabled; } }; const hooks = new Store(); function useSize(props) { // 组件尺寸上下文 const xeSizeInfo = inject('xeSizeInfo', null); const computeSize = computed(() => { return props.size || (xeSizeInfo ? xeSizeInfo.value : null); }); provide('xeSizeInfo', computeSize); return { computeSize }; } function usePermission(props) { const computePermissionInfo = computed(() => { return handleCheckInfo(props.permissionCode, props.permissionMethod); }); return { computePermissionInfo }; } const useFns = { useSize, usePermission }; const installedPlugins = []; function use(Plugin, options) { if (Plugin && Plugin.install) { if (installedPlugins.indexOf(Plugin) === -1) { Plugin.install(VxeUI, options); installedPlugins.push(Plugin); } } return VxeUI; } const components = {}; function getComponent(name) { return components[name] || null; } function hasComponent(name) { return !!components[name]; } function component(comp) { if (comp && comp.name) { components[comp.name] = comp; components[XEUtils.kebabCase(comp.name)] = comp; } } function renderEmptyElement() { return createCommentVNode(); } function checkVersion(version, pVersion, sVersion) { if (version) { const vRest = `${version}`.match(/(\d+).(\d+).(\d+)/); if (vRest) { const pV = XEUtils.toNumber(vRest[1]); if (sVersion) { const sV = XEUtils.toNumber(vRest[2]); return pV >= pVersion && sV >= sVersion; } return pV >= pVersion; } } return false; } const VxeUI = Object.assign(VxeCore, { renderEmptyElement, setTheme, getTheme, setConfig, getConfig: getConfig, setIcon, getIcon: getIcon, renderGlobalIcon, renderCustomIcon, setLanguage, hasLanguage, getLanguage, setI18n, getI18n, globalEvents, GLOBAL_EVENT_KEYS, createEvent, globalResize, renderer, validators, menus, formats, commands, interceptor, clipboard, log, permission, globalStore, hooks, component, getComponent, hasComponent, useFns, getSlotVNs, checkVersion, use }); setTheme(); export { GLOBAL_EVENT_KEYS, VxeCore, VxeUI, checkVersion, clipboard, commands, component, coreVersion, createEvent, VxeUI as default, formats, getComponent, getConfig, getI18n, getIcon, getLanguage, getSlotVNs, getTheme, globalEvents, globalResize, globalStore, handleCheckInfo, hasComponent, hasLanguage, hooks, interceptor, log, menus, permission, renderCustomIcon, renderEmptyElement, renderGlobalIcon, renderer, setConfig, setI18n, setIcon, setLanguage, setTheme, use, useFns, usePermission, useSize, validators };