vue2使用习惯了以后,mixins这种复用性极高的功能肯定是避免不了常用的,当使用vue3的时候,也想要类似于mixins这种功能,应该咋弄呢。
1.vue2的mixins中有data,watch,methods, mounted等,对应vue3中hooks的写法是咋样的。
先拿出一个完整的hooks来看吧,写法是自己参考网上百度到的进行改进,也可根据自己的需要再改。
myHooks.tsx
import { Select, SelectOption } from 'ant-design-vue'
export default function (props: any) {
const countValue= ref(1)
const selectList = ['张三', '李四', '王五']
let columns = [
{
title: '姓名',
dataIndex: 'name',
align: 'center',
customRender: ({ record }: { record: any }) => {
return (
<div>
<Select v-model:value={record.name} placeholder="" onChange={(e:any)=>nameChange(e)}>
{selectList.map((item: any,dex:any) => {
return <SelectOption key={dex} value={item}> { item } </SelectOption>
})}
</Select>
</div>
)
}
},
{
title: '年龄',
dataIndex: 'age',
align: 'center'
},
{
title: '身高',
dataIndex: 'height',
align: 'center'
}
]
onMounted(() => {
console.log('onMounted')
})
watch(
() => props.group,
val => {
nameChange(0)
}
)
function nameChange(val: any) {
console.log(val)
countValue.value += 1
}
return { columns, nameChange}
}
上面的ref对应vue2中mixins的data变量,onMounted对应vue2的mixins生命周期,watch也是一样,函数直接写在最外层即可。
2.在页面中引用这个myHooks.tsx时,就是下面这样
<template>
<a-table bordered :columns="columns" :pagination="false" :data-source="list"> </a-table>
</template>
<script setup lang="tsx">
import myHooks from '/myHooks'
const props = defineProps({
list: {
type: Array,
default: () => [],
required: true
},
group: {
type: String,
default: () => ''
}
})
let columns = ref([
{
title: '分组',
dataIndex: 'group',
align: 'center'
},
{
title: '业务',
dataIndex: 'bussiness',
align: 'center'
},
{
title: '费用',
dataIndex: 'total',
align: 'center'
}
])
let obj: any = myHooks(props)
columns.value.push(...obj.columns)
</script>
在组件的最外层调用myHooks会执行里面的生命周期,watch等。通用性也很高,可以将复用的逻辑全部封装到里面。像table组件的分页逻辑,删除第二页只有一条数据时,切换到第一页等功能完全可以用hooks这种方式实现。不用再每次写页面一次次写里面的逻辑,直接调hooks,把方法导入就行。
3.and-design-vue中table用法,封装分页和请求功能。
myPage.tsx
import { Table, Button } from 'ant-design-vue'
import useTable from 'useTable'
export default defineComponent({
setup(props, { emit }) {
const columns: any = [
{ title: '姓名', dataIndex: 'name', align: 'center' },
{ title: '年龄', dataIndex: 'age', align: 'center' },
{ title: '性别', dataIndex: 'sex', align: 'center' }
]
const serves = (obj: any) => {
return axios.get(`https://baidu.com`, { params: obj })
}
const { data, run, loading, params, tableChange, paginationConfig } = useTable(serves)
function search(e: any) {
let vo = {
current: 1,
size: 10,
keyword: e.keyword || '',
}
run(vo)
}
return () => {
return (
<div>
<Button onClick={()=>{search}}>搜索</Button>
<Table
scroll={{ x: 600 }}
columns={columns}
loading={loading.value}
bordered
data-source={data.value?.records || []}
onChange={tableChange}
pagination={paginationConfig}
/>
</div>
)
}
}
})
useTable.ts
import { useRequest } from 'vue-request'
import { Options } from 'vue-request/dist/types/index'
import { ref } from 'vue'
const useTable = (service: any, pageConfig?: any, option?: Options<any, any>) => {
const current = ref(1)
const pageSize = ref(10)
const paginationConfig: any = ref({
total: 0,
showTotal: (e: any) => `共${e}条记录`,
showSizeChanger: true,
showQuickJumper: true,
current: 1,
pageSize: 10
})
let curentKey = pageConfig?.current || 'current'
let pageSizeKey = pageConfig?.pageSize || 'pageSize'
const { data, run, refresh, loading, params, error } = useRequest(
async p => {
const res = await service(p)
return res.data
},
{
manual: true,
onSuccess: () => {
current.value = params.value[0][curentKey]
pageSize.value = params.value[0][pageSizeKey]
Object.assign(paginationConfig.value, { total: data.value?.total || 0, current: current.value, pageSize: pageSize.value })
},
...option
}
)
function tableChange(v: any) {
run({
...params.value[0],
[curentKey]: v.current,
[pageSizeKey]: v.pageSize
})
}
function refreshList(type?: 'del') {
if (type === 'del' && data.value?.data.size === 1) {
run({
...params.value[0],
[curentKey]: params.value[0].current - 1
})
} else {
refresh()
}
}
return {
data,
loading,
error,
params,
run,
paginationConfig,
refresh: refreshList,
tableChange
}
}
export default useTable