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><Tablescroll={{ x: 600 }}columns={columns}loading={loading.value}bordereddata-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