# 风格
vue3.0拥有多种不同的开发风格,首先是.vue
文件支持v2的选项式api,还有v3的新特性组合式api,这里不做介绍,tsx的开发风格也有两种,一是直接.tsx
文件开发,二是.vue
文件中用<script lang="tsx">
,这两种tsx风格在具体编码时,也会有风格变化,比如是否使用render(){}
函数,还是在setup(){}
中直接return一个箭头函数来渲染dom。
# tsx格式文件
海豚调度系统全站都是用.tsx开发,后面会总结纯tsx开发的经验。 tsx文件开发vue组件需要重点了解以下:
- defineComponent函数
为了让 TypeScript 正确地推导出组件选项内的类型。不加这个那么就不会有任何vue提示。
import { defineComponent } from 'vue'
const Content = defineComponent({
name: 'DSContent',
setup() {}
})
export default Content
- 渲染Dom方式
render(){}
函数
import { defineComponent } from 'vue'
const Content = defineComponent({
name: 'DSContent',
setup() {
const name = 111
return {name}
//把render中需要的变量return出来,使用的时候需要加this,
//响应式变量自动解构即使用时无需加value
},
render(){
return (
<div>{this.name}</div>
)
}
})
export default Content
setup(){}
中直接return
import { defineComponent } from 'vue'
const Content = defineComponent({
name: 'DSContent',
setup() {
const name = 111
return (
<div>{name}</div>
)
},
})
export default Content
- 思考,这两种方式同时存在哪个优先级高?更推荐哪种?
测试证明,哪个写在前面哪个就先执行。
第一种直接return的方式,可少写代码,使用时也不用this,缺点是代码相对杂乱,第二种render函数的方式虽然多写了一些代码,但是有边界感,可以清晰的定位需要的对象及渲染部分。
- 动态值 在 TSX 表达式中,使用大括号来嵌入动态值:更多渲染参看文档 (opens new window)
<div id={dynamicId} onClick={this.handle}> hello, {userName} </div>
<div onClick={(event) => { this.handle(item) }}> 事件传参 </div>
# vue格式文件写tsx
在vue文件中通过<script lang="tsx">
<script lang="tsx">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'xxx',
props: {},
setup(props, { attrs, emit, slots, expose }) {
...
return () => {
return(
<div/>
)
}
},
})
</script>
<style lang="less" scoped>
:deep(.class){}
</style>
要说这种方式的优点,就是写css方便,纯tsx格式文件不能用style
,只能用css-module 相对麻烦点。
其实这种也可以用render,甚至可以用template,当他们俩共存时,render优先级更高,当然这俩种形式不是主流,如果混乱使用可能被当成另类。
# 总结
开发中应该选择何种方式开发呢,首选单文件组件 (opens new window)的方式开发,复杂的组件可以用vue格式写tsx开发。当然也可以像某些系统一样,全站都有.tsx文件,这种更适合习惯tsx的程序员。
# 全站tsx的经验分享
规范性做法一个组件分三个文件
- index.tsx 参考 tsx格式文件-渲染方式- render(){}函数,这里是编写组件的文件
import { defineComponent, ref } from 'vue'
import { NLayout, NLayoutContent, NLayoutHeader, useMessage } from 'naive-ui'
import SideBar from './components/sidebar'
import { useDataList } from './use-dataList'
const Content = defineComponent({
name: 'DSContent',
setup() {
const {
state, //数据
changeMenuOption, //方法
} = useDataList()
onMounted(() => {
changeMenuOption(state) //根据业务页面加载完成执行
})
//把解构的数据和方法return给渲染使用
return {
...toRefs(state),
changeMenuOption,
}
},
render() {
return (
<NLayout style='height: 100%'>
<NLayoutHeader style='height:167px'>
....
</NLayoutHeader>
<NLayout has-sider position='absolute' style='top:167px'>
{this.isShowSide && (
<SideBar/>
)}
<NLayoutContent
native-scrollbar={false}
style='padding: 16px 22px'
contentStyle={'height: 100%'}
>
<router-view key={this.$route.fullPath} />
</NLayoutContent>
</NLayout>
</NLayout>
)
}
})
- index.module.css 模块化css 给tsx使用
import styles from './index.module.scss'
<div class={[styles.menu_box, styles['right-menu'],'tab-vertical']}></div>
.menu_box{
overflow-x: auto;
.right-menu {
width:100%;
}
}
:global(.tab-vertical){
width:100%
}
index.module.scss 中的样式会自动渲染成带作用域选择器,html中{styles.xxx}
也会渲染成带作用域的类名,这样就实现了scope的功能。
如果要覆写组件样式或者不希望带作用域,用:global
- use-datalist.ts
一些数据的定义,或一些方法可以抽出来放在这里,目的是让组件代码简洁,把功能全写在ts里,有点网页三剑客时代的感觉,js代码单独抽出来,tsx当作html,css-modele当作css。
分享ts里的书写思路:
定义一个reactive
响应数据,定义一些方法如异步请求、业务操作等,最终导出给html使用
const variables = reactive({
columns: [],
tableWidth: DefaultTableWidth,
tableData: [],
page: ref(1),
pageSize: ref(10),
searchVal: ref(null),
totalPage: ref(1),
showModalRef: ref(false),
statusRef: ref(0),
row: {},
loadingRef: ref(false)
})
//异步请求
const getTableData = (params: any) => {
const { state } = useAsyncState(
queryProjectListPaging(params).then((res: ProjectRes) => {
variables.tableData = res.totalList as any
variables.loadingRef = false
}),
{}
)
return state
}
//最终导出
return {
variables,
getTableData
}
使用
import { useTable } from './use-table'
const list = defineComponent({
setup(){
const { variables, getTableData, createColumns } = useTable()
//可以定制一些业务方法,组织好参数,灵活运用吧
const requestData = () => {
getTableData({
pageSize: variables.pageSize,
pageNo: variables.page,
searchVal: variables.searchVal
})
}
return {
...toRefs(variables),
requestData,
}
},
render() {
return (
<NDataTable data={this.tableData}/>
)
}
})
export default list