直接用模板编写
<a-menu v-model:selectedKeys="selectedKeys" mode="inline" theme="light"> <a-menu-item key="1"> <pie-chart-outlined/> <span>工作台</span> </a-menu-item> <a-sub-menu key="sub3"> <template #title> <span> <desktop-outlined/> <span>系统配置</span> </span> </template> <a-sub-menu key="sub4" title="权限管理"> <a-menu-item key="7"> 菜单列表 </a-menu-item> </a-sub-menu> </a-sub-menu> <a-sub-menu key="sub2"> <template #title> <span> <user-outlined/> <span>User</span> </span> </template> <a-menu-item key="4">Bill</a-menu-item> </a-sub-menu> </a-menu>
使用tsx编写
数据结构
const defaultMenu = [ { name: '首页', router: '/home', icon: 'HomeFilled', isShow: 1, id: 1 }, { name: '组件库', router: '', isShow: 1, id: 2, children: [ { name: 'Markdown编辑器', router: '/markdown', icon: 'HomeFilled', isShow: 1, id: 3, }, { name: '文件上传', router: '/fileUpload', icon: 'UploadOutlined', isShow: 1, id: 4, children:[ { name: '图片上传', router: '/fileUploadImg', icon: 'UploadOutlined', isShow: 1, id: 6, } ] }, ] }, { name: '关于', router: '/about', icon: 'UserOutlined', isShow: 1, id: 5, }, ] import {computed, defineComponent, h, ref} from 'vue' import {useStore} from 'vuex' export default defineComponent({ name: 'yxs-menu-slider', setup() { const store = useStore(); const selectedKeys = ref<string[]>(['1']); // 设置默认选中 const menuList = computed(() => store.getters.menuList); // 等于上述的 defaultMenu 结构,我只不过放在了store return { selectedKeys, menuList } }, render(ctx: any) { const deepMenu = function (list: Array<any>) { let html = null; return list.filter((item: any) => item.isShow).map((item: any) => { if (item.children && item.children.length) { html = h( <a-sub-menu key={item.id}></a-sub-menu>, {}, { title: () => { // 插槽位置 title return <span>{item.name}</span> }, default: () => { // 默认内容 let children = item.children.map((todo: any) => { return <a-menu-item key={todo.id}>{todo.name}</a-menu-item> }) return children && deepMenu(item.children) // 递归 } } ) } else { html = h( <a-menu-item key={item.id}></a-menu-item>, {}, { default: () => { return <span>{item.name}</span> } } ) } return html; }) } const children = deepMenu(ctx.menuList); return ( <div class="yxs-menu-slider"> <a-menu v-model:selectedKeys={ctx.selectedKeys} mode="inline" theme="light"> {children} </a-menu> </div> ) } })
使用
注册调用即可 <template> <YxsMenuSlider/> </template> <script lang="ts"> import YxsMenuSlider from './components/menu/index.tsx' export default defineComponent({ name: 'Slider', components: { YxsMenuSlider } }) </script>
效果如下
上面半截是模板,下面tsx模板
扩展
你的组件可能有更多的插槽,写上插槽名字即可
h(Comp, null, { default: () => 'default', foo: () => 'foo', bar: () => 'bar' })
注意这么写的时候,即便没有props,第二个参数也是必须的,因为h函数发现第二个参数如果是对象,那么默认其就是props,
更多写法请往下看,源码已经帮我做好了很多兼容
讲解
h语法
在讲之前先看h函数源码 // type 元素的类型 // propsOrChildren 数据对象, 这里主要表示(props, attrs, dom props, class 和 style) // children 子节点也是一个any类型 export function h(type: any, propsOrChildren?: any, children?: any): VNode { if (arguments.length === 2) { if (isObject(propsOrChildren) && !isArray(propsOrChildren)) { // single vnode without props if (isVNode(propsOrChildren)) { return createVNode(type, null, [propsOrChildren]) } // props without children return createVNode(type, propsOrChildren) } else { // omit props return createVNode(type, null, propsOrChildren) } } else { if (isVNode(children)) { children = [children] } return createVNode(type, propsOrChildren, children) } }
通过上述我们就知道,如何使用h函数,以及为什么能这么传参
h('div') // type + props h('div', {}) // type + omit props + children // Omit props does NOT support named slots h('div', []) // array h('div', 'foo') // text h('div', h('br')) // vnode h(Component, () => {}) // default slot // type + props + children h('div', {}, []) // array h('div', {}, 'foo') // text h('div', {}, h('br')) // vnode h(Component, {}, () => {}) // default slot h(Component, {}, {}) // named slots // named slots without props requires explicit `null` to avoid ambiguity h(Component, null, {})