vue3 代码拆分最佳实践?

老项目遗留了一些代码,VUE页面里面的代码太长了
想把TS代码拆分出来,请问最佳实践是什么样子的?
旧代码:

<template>

<div class="table-tree-container">

<div class="list-tree-wrapper">

<div class="list-tree-operator">

<t-input v-model="filterText" placeholder="请输入过滤关键词" @change="onTreeInput">

<template #suffix-icon>

<search-icon size="var(--td-comp-size-xxxs)" />

</template>

</t-input>

<t-button block @click="onCleanActive" variant="dashed" size="small" class="mt-2">

<template #icon>

<i class="ri-close-circle-line mr-1"></i>

</template>

清空选中项

</t-button>

<t-tree class="mt-2" :data="categoryTree" activable v-model:actived="treeActived" @active="onTreeActive" :filter="filterByText" expand-all :keys="{ value: 'id', label: 'cate_name' }" hover expand-on-click-node />

</div>

<div class="list-tree-content">

<div class="index-container">

<t-card :bordered="false" :title="cardTitle" class="list-card-container">

<template #actions>

<t-button @click="onAdd" v-permission="'article/add'">

<template #icon>

<i class="ri-add-line mr-1"></i>

</template>

添加

</t-button>

</template>

<t-space>

<t-select :options="REC_OPTIONS" v-model="searchForm.rec" clearable placeholder="请选择推荐位" />

<t-select :options="STATUS_OPTIONS" v-model="searchForm.status" clearable placeholder="请选择状态" />

<t-input v-model="searchForm.kw" placeholder="请输入你需要搜索的内容" clearable />

<t-button @click="onSearch" theme="default">

<template #icon>

<i class="ri-search-line mr-1"></i>

</template>

搜索

</t-button>

<t-dropdown :options="DROPDOWN_OPTIONS" :max-column-width="200">

<t-button variant="outline" theme="success"> 选中项 <i class="ri-arrow-down-s-line ml-1 icon-valign-top"></i> </t-button>

</t-dropdown>

</t-space>

<t-row :gutter="16" class="table-container">

<t-col>

<t-table :data="data" stripe :columns="TABLE_COLUMNS" :vertical-align="'top'" :hover="true" :pagination="pagination" @select-change="onSelectChange" @page-change="onPageChange" :loading="dataLoading" :row-key="'id'">

<template #id="{ row }">

<var>{{ row['id'] }}</var>

</template>

<template #status="{ row }">

<t-tag v-if="Number(row['status']) === 1" theme="success" variant="light"> 公开</t-tag>

<t-tag v-else-if="Number(row['status']) === 0" theme="danger" variant="light"> 锁定</t-tag>

<t-tag v-else theme="primary" variant="light"> 定时发布</t-tag>

</template>

<template #sort_by="{ row }">

<t-input-number v-permission="'article/sort'" v-model="row.sort_by" @change="(v) => onSortChange(row, v)" theme="column"></t-input-number>

</template>

<template #created_at="{ row }">

{{ formatTime(row['created_at']) }}

</template>

<template #cid="{ row }">

{{ formatCate(row['cid']) }}

</template>

<template #author="{ row }">

{{ row['author'] }}

</template>

<template #op="{ row }">

<a class="t-button-link" v-permission="'article/edit'" @click="onEdit(row)">编辑</a>

</template>

</t-table>

</t-col>

</t-row>

</t-card>

</div>

</div>

</div>

</div>

</template>

<script setup lang="ts">

import { ref, onMounted, reactive } from 'vue';

import { MessagePlugin, DialogPlugin } from 'tdesign-vue-next';

import { STATUS_OPTIONS, REC_OPTIONS } from '@/config/global';

import helper from '@/utils/helper';

import { getArticleList, updateArticleSort, updateArticleStatus, deleteArticle } from '@/api/article';

import { IApiResponse } from '@/types';

import { TABLE_COLUMNS } from '@/pages/article/constants';

import { useRouter } from 'vue-router';

import { getArticleStore } from '@/store';

const router = useRouter();

const cardTitle = ref(helper.getPageTitle());

const cateId = ref(0);

const categoryTree = ref([]);

const articleStore = getArticleStore();

const fetchCategoryTree = async () => {

const { treeList } = articleStore;

if (helper.len(treeList) === 0) {

try {

await articleStore.getTreeCategory();

categoryTree.value = articleStore.treeList;

} catch (e) {

return Promise.reject(e);

}

} else {

categoryTree.value = treeList;

}

};

const formatCate = (v) => {

if (helper.len(categoryTree.value) <= 0) {

return '';

}

let item = categoryTree.value.find((ele) => {

if (Number(ele.id) === Number(v)) {

return ele;

}

return null;

});

if (!item) {

return v;

}

return item.cate_name;

};

const formatTime = (v) => {

if (!v) {

return '';

}

return helper.time().dateTimeDisplay(v);

};

const onAdd = () => {

let url = '/article/add';

if (cateId.value) {

url += '?cate_id=' + cateId.value;

}

router.push(url);

};

const onEdit = (row) => {

router.push('/article/edit?id=' + row.id);

};

const onSearch = () => {

fetchData(searchForm.value);

};

const data = ref([]);

const dataLoading = ref(false);

const pagination = reactive({

current: 1,

pageSize: Number(import.meta.env.VITE_APP_PAGE_SIZE),

total: 0,

showJumper: true,

});

const searchForm = ref({

kw: '',

cid: null,

rec: null,

status: null,

page: pagination.current,

page_size: pagination.pageSize,

});

const onSortChange = async (row, value) => {

try {

helper.fullLoading();

console.log(value, row);

const resp: IApiResponse = await updateArticleSort({ id: row.id, value: value });

if (resp.code === 0) {

MessagePlugin.success('操作成功');

await fetchData();

} else {

return Promise.reject(new Error(resp.message));

}

} catch (e) {

MessagePlugin.error(e.message);

} finally {

helper.hideLoading();

}

};

const onPageChange = async (pageInfo) => {

const { current, pageSize } = pageInfo;

pagination.current = current;

pagination.pageSize = pageSize;

await fetchData({ page: current, page_size: pageSize });

};

const onSelectChange = (value) => {

selection.value = value;

};

const fetchData = async (params = null) => {

dataLoading.value = true;

try {

let def = { ...searchForm.value };

if (params) {

def = Object.assign(def, params);

}

const res: IApiResponse = await getArticleList(def);

if (res.code === 0) {

const { data_list = [] } = res.data;

data.value = data_list;

pagination.total = res.data.total_count;

} else {

return Promise.reject(new Error(res.message));

}

} catch (e) {

data.value = [];

console.log(e);

//MessagePlugin.error(e.message);

pagination.total = 0;

} finally {

dataLoading.value = false;

}

};

const onTreeActive = async (v, c) => {

searchForm.value.cid = c.node.data.id;

router.push({

query: {

cate_id: searchForm.value.cid,

},

});

await fetchData();

};

const onCleanActive = async () => {

router.push({

query: {},

});

searchForm.value.cid = null;

treeActived.value = [];

await fetchData();

};

const treeActived = ref([]);

const filterByText = ref();

const filterText = ref();

const onTreeInput = () => {

filterByText.value = (node) => {

const rs = node.label.indexOf(filterText.value) >= 0;

return rs;

};

};

onMounted(async () => {

cateId.value = helper.getQueryToNumber('cate_id', router);

if (cateId.value) {

searchForm.value.cid = cateId.value;

}

await fetchCategoryTree();

await fetchData();

});

const selection = ref([]);

const DROPDOWN_OPTIONS = [

{

content: '删除选中内容',

value: 2,

onClick: () => {

dropdownClick({ value: 2 });

},

},

{

content: '修改为公开',

value: 1,

onClick: () => {

dropdownClick({ value: 1 });

},

},

{

content: '修改为隐藏',

value: 0,

onClick: () => {

dropdownClick({ value: 0 });

},

},

];

const onStatus = async (params) => {

try {

helper.fullLoading();

const resp: IApiResponse = await updateArticleStatus(params);

if (resp.code === 0) {

MessagePlugin.success('操作成功');

await fetchData();

} else {

return Promise.reject(new Error(resp.message));

}

} catch (e) {

MessagePlugin.error(e.message);

} finally {

helper.hideLoading();

}

};

const onDelete = async (params) => {

const dialogNode = DialogPlugin.confirm({

header: '系统提示',

body: '确定要删除吗?',

theme: 'info',

onConfirm: async () => {

dialogNode.hide();

await deleteAction(params);

},

});

};

const deleteAction = async (params) => {

try {

helper.fullLoading();

const resp: IApiResponse = await deleteArticle(params);

if (resp.code === 0) {

MessagePlugin.success('操作成功');

await fetchData();

} else {

return Promise.reject(new Error(resp.message));

}

} catch (e) {

MessagePlugin.error(e.message);

} finally {

helper.hideLoading();

}

};

const dropdownClick = (data) => {

if (data.value === 1 && helper.len(selection.value) === 0) {

MessagePlugin.warning('请选择要操作的数据');

return false;

}

let params = { ids: selection.value.join(',') };

if (data.value === 2) {

onDelete(params);

} else {

params['status'] = data.value;

onStatus(params);

}

};

</script>

<style lang="less" scoped>

.table-tree-container {

background-color: var(--td-bg-color-container);

border-radius: var(--td-radius-medium);

.t-tree {

margin-top: var(--td-comp-margin-xxl);

}

}

.list-tree-wrapper {

overflow-y: hidden;

background: #fff;

}

.list-tree-operator {

width: 210px;

float: left;

padding: var(--td-comp-paddingTB-xxl) var(--td-comp-paddingLR-xxl);

}

.list-tree-content {

border-left: 1px solid var(--td-border-level-1-color);

overflow: auto;

}

</style>


回答:

没仔细看你的代码,说说我的重构经验:

  1. 上下文不相关的函数,抽出来放到工具函数里。包括网络请求,都可以抽出来。
  2. 能够复用的功能,抽出来做成组件。组件的颗粒度以 方便理解 为准,细一点没关系。
  3. 样式我已经完全拥抱 TailwindCSS 了,所以几乎不存在 <style>

以上是 vue3 代码拆分最佳实践? 的全部内容, 来源链接: utcz.com/p/934804.html

回到顶部