结尾
最近在学习vue3(应用开发层面),做了一些小demo我的项目,像[md-editor-v3],vue3-admin等。喜爱在vue我的项目中应用jsx
语法来编写,简直我的项目中都应用到了ts
,某一些写法,在谷歌的时候没找到,所以想做一个小总结。
之前看他人探讨过在我的项目中使
ts
的态度,作者持保留态度,有些中央会减少代码量,如果不相熟的话,甚至会耽搁开发进度。然而从开发公共组件及某些复用组件来看,ts会帮助开发,而且可能减少浏览性。
如果文章内容有谬误,请帮助指出。
ts中的props
该问题次要存在于应用了ts
开发的我的项目中,不区别是否应用jsx
,从 string、string/object混合、array 角度演示(default值没有写出)。
js开发组件中,props类型验证会像上面这样写
props: {
propA: String,
propB: [String, Object],
propC: [Array]
}
如果A只能是a\b\c
三个中的一个,B如果只能是css款式,对象就须要限度,C只能是数据中存在a/b/c
中的组合,你可能会用到validator
。然而没有类型,对开发提醒不敌对。
于是应用ts替换一下写法,
import { PropType, CSSProperties } from 'vue';
props: {
propA: String as PropType<'a' | 'b' | 'c'>,
propB: [String, Object] as PropType<string | CSSProperties>,
propC: [Array] as PropType<Array<'a' | 'b' | 'c'>>,
}
能领会到的不言而喻的益处就是上面这样:
懒人必备的代码提醒~
看过ant-design-vue的源码的话,会发现他们应用了一个叫
vue-types
的库来封装了类型,适合的能够间接应用这种形式,传送门不必去给
setup
的第一入参定义类型,会和props抵触,感兴趣的能够试试。
jsx中的插槽
这个在vue3-admin中有用card组件做过演示,传送门
开发组件须要留神的是,如果让组件更好的反对jsx的话,就须要思考组件的插槽内容是通过props
传递的还是通过插槽的形式传递的,前者多呈现在jsx
语法中,而后者则少数状况是.vue
模板语法中。
剖析card组件
import { SetupContext, EmitsOptions, } from 'vue';
setup(props, ctx: SetupContext<EmitsOptions>) {
return () => {
// 插槽获取肯定在函数组件(render)办法外部,否则提醒:this will not track dependencies used in the slot
const slotDefault = getSlot({ ctx });
const slotTitle = getSlot({ props, ctx }, 'title');
const slotFunc = getSlot({ props, ctx }, 'func');
const cardClass = classnames('vra-card', props.border && 'vra-card-border');
const headerClass = classnames('vra-card-header', props.headerClass);
const bodyClass = classnames('vra-card-body', props.bodyClass);
return (
<div class={cardClass}>
{slotTitle && (
<div class={headerClass} style={props.headerStyle}>
<div class="vra-card-title">{slotTitle}</div>
{slotFunc && <div class="vra-card-func">{slotFunc}</div>}
</div>
)}
<div class={bodyClass} style={props.bodyStyle}>
{slotDefault}
</div>
</div>
);
};
}
getSlot办法是用来依据名称来主动获取起源中的插槽内容的,不论是vue插槽的形式,还是jsx的属性的形式,代码:
import { ComponentPublicInstance, SetupContext, EmitsOptions } from 'vue';
/**
* 获取指定插槽内容
* 办法设定:vue组件中v-slot优先级高于props
*
* @param param0 组件实例instance,SetupContext(setup二入参),props
* @param name 插槽名或者props名
* @returns VNode
*/
export const getSlot = (
{
instance,
ctx,
props = {}
}: {
instance?: ComponentPublicInstance;
ctx?: SetupContext<EmitsOptions>;
props?: any;
},
name = 'default'
) => {
const targetSlot = instance?.$slots[name] || ctx?.slots[name];
return (targetSlot ? targetSlot(instance) : '') || props[name];
};
card组件中正文内容插槽获取肯定在函数组件(render)办法外部,该问题的解释为:因为插槽内容是咱们通过办法手动获取的,理解过setup
的就晓得,它在整个生命周期中,只会执行一次,无论后续是否有状态变更,如果在setup
中获取到插槽内容,那么后续插槽内容如果有更新,则在card中不会有相应的扭转。相同,如果是在setup
中的render
函数或则在内部render
函数中,每次状态变更,render
函数均会执行,及保障了最新的插槽内容能获取到。
jsx中的双向绑定
尽管可能实现应用指令,但还是不必做这个打算,jsx中均能够用js语法来代替(坚固下根底也没故障,之前看过一个问答说jsx中怎么v-if,答复让人深思:js的if else都不会了么?)。
原生的输出标签可能应用vModel
实现双向绑定机制,例如input、textarea等
import { defineComponent, reactive, watchEffect } from 'vue';
export default defineComponent({
setup() {
const test = reactive({
a: 1
});
watchEffect(() => {
console.log(test.a);
});
return () => <input vModel={test.a} />;
}
});
演示:
tsx中会提醒vModel
不存在,这时就须要本人定义type了,作者没有应用这种形式所以没有进一步尝试。我的项目中都是自行绑定数据
setup() {
const val = ref('')
return () => <input value={val.value} onChang={({ target }: Event) => (val.value = (target as HTMLTextAreaElement).value)} />
}
target须要断言能力失常,这样看起来好像写的代码更多了,啊哈!
antd的图标
这一项个别呈现在开发admin我的项目时,配置左侧菜单,像上面这样:
ant-design当初react ui库和vue ui库都将icon剔进来了,独自引入一个依赖来应用icon,按需加载,确实不便,可是,当初要实现在数据库中配置菜单对应的icon,而后在获取路由配置的时候拿过去显示,办法就只有两种:
- 将
@ant-design/icons-vue
的所有组件导入,再做一个枚举,在服务端配置组件名称,渲染时依据组件名称匹配组件,像这样:
key-element文件
import { WifiOutlined, WomanOutlined } from '@ant-design/icons-vue'
export default {
WifiOutlined: <WifiOutlined />,
WomanOutlined: <WomanOutlined />
}
应用
const router = [{path: '/index',meta: { title: '首页', icon: 'WifiOutlined' },}]
// render
<div>{ keyElement[routerItem.meta.icon] }</div>
这样不迷信,icon太多。上面的办法得以优化。
- 原理差不多,也是将全副导入,然而不是本人手动导入:
import { h } from 'vue';
// 导入所有组件
import * as Icon from '@ant-design/icons-vue';
// 已获取到的配置
const router = [{path: '/index',meta: { title: '首页', icon: 'WifiOutlined' },}]
// render
<div>{ h(Icon[router.meta.icon]) }</div>
不出意外应用了ts会提醒以下谬误:
(property) MenuType.iconName?: any Element implicitly has an ‘any’ type because expression of type ‘any’ can’t be used to index type…
这里须要给meta.icon指明类型:
import Icon from '@ant-design/icons-vue/lib/icons';
export interface MenuType {
path: string;
children?: Array<MenuType>;
meta?: {
icon?: keyof typeof Icon;
}
// 其余类型
// ...
}
const router: MenuType[] = [{path: '/index',meta: { title: '首页', icon: 'WifiOutlined' }}]
vue3的h办法和react的creatElemet办法相似。
结尾
临时写到这儿,前面想到再更新吧,都比拟根底,看一遍就晓得了。
发表回复