UNPKG

magiccube-vue3

Version:

vue3-js版组件库

173 lines (153 loc) 4.89 kB
import { ref, computed, nextTick, h, resolveDynamicComponent, watch } from 'vue' const Tab = { name: 'McTab', props: { modelValue: [String, Number], data: Object, options: Array, labelName: { type: String, default: 'name' }, valueName: { type: String, default: 'value' }, type: String }, emits: ['update:modelValue', 'change'], setup(props, { emit }) { const styleData = ref({}) const tabEl = ref(null) const handleClick = (e, item) => { const _val = item[props.valueName] if (_val === props.modelValue || item.disabled) return setSubscript(e.target) model.value = _val } const setSubscript = (target) => { styleData.value = { left: target.offsetLeft + 'px' } } const model = computed({ get() { return props.modelValue }, set(value) { emit('update:modelValue', value) emit('change', value) } }) nextTick(() => { if (tabEl.value) { setSubscript(tabEl.value) } }) watch(() => model.value, async (nv, ov) => { if(ov !== nv && props.type === 'box'){ await nextTick() tabEl.value.scrollIntoView() } }) const innerNode = (item, idx) => { const isActive = model.value === item[props.valueName]; const isDisabled = item.disabled; return ( <span class={{ 'mc-tab__inner': true, 'mc-tab-active': isActive, 'mc-tab-disabled': isDisabled }} ref={isActive ? tabEl : ''} key={idx} onClick={(e) => handleItemClick(e, item)}> { escapeHtml(item[props.labelName]) } {/* icon图标,需要传入vue template格式的组件 */ renderTabIcon(item.tabIcon) } { renderBadge(item.badge) } { renderData(props.data, item.key) } </span> ); } // 处理点击事件 const handleItemClick = (e, item) => { try { handleClick(e, item); } catch (error) { console.error('Error in handleClick:', error); } }; // 渲染图标 const renderTabIcon = (tabIcon) => { if (tabIcon && isTrustedComponent(tabIcon)) { return ( <i class="mc-tab__inner--icon"> {h(resolveDynamicComponent(tabIcon), {})} </i> ); } return null; }; // 渲染徽章 const renderBadge = (badge) => { if (badge && badge !== '0') { return ( <i class="mc-tab__inner--badge">{ badge }</i> ); } return null; }; // 渲染数据 const renderData = (data, key) => { if (data && data[key]) { return ( <i class="mc-tab__inner--count">{ data[key] }</i> ); } return null; }; // 转义HTML const escapeHtml = (unsafe) => { return unsafe .replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;') .replace(/'/g, '&#039;'); }; // 验证组件是否可信 const isTrustedComponent = (component) => { // 这里可以根据实际情况实现具体的验证逻辑 return true; // 示例中假设所有组件都是可信的 }; return () => ( <div class={{ 'mc-tab': true, 'mc-tab-card': props.type === 'card', 'mc-tab-box': props.type === 'box' }}> { props.options.map(innerNode) } <span class={{ 'mc-tab__subscript': true, 'mc-tab-card': props.type === 'card', 'mc-tab-box': props.type === 'box' }} style={styleData.value}></span> </div> ) } } Tab.install = (app) => { app.component(Tab.name, Tab) } const McTab = Tab export { McTab, McTab as default }