(假设是二层结构) ----> 参考【八、页面结构(封装结构)】
(创建对应的vue文件结构【主文件和对应组件文件】)
(导入组件,并能正确展示)
(html+css的东西)
(用假数据)(props/emit等)----> 【三、搜索栏的二次封装】和【五、表格的二次封装(简单版)】
(发送接口请求)---->【 四、数据获取和保存的逻辑】
src/components/nav-menu.vue
1.1、Template标签中,图片引用要通过“~@/”方式。
1.2、Template标签可以使用v-for循环。
1.3、Template标签可以使用v-if判断。
1.4、v-for+v-if结合,当v-if为真时,渲染某一元素/动态绑定某一属性。
注意:v-if,也可以写在组件中,或者UI组件库中,控制组件是否显示
src/base-ui/from/src/form.vue
1.16、Template标签使用v-if判断。
src/components/nav-menu.vue
1.5、引入store。import { useStore } from 'vuex'
1.6、实例store对象。const store = useStore()
1.7、获取store对象的属性(computed计算属性)。const userMenus = store.state.login.userMenus
src/components/page-content.vue
1.19、通过setup(props) +store.dispatch(props.属性)可以动态传入参数。setup(props) {store.dispatch('接口', {pageName: props.pageName})}
export default defineComponent({
props: {
pageName: {
type: String,
required: true
}
},
setup(props) {
const store = useStore()
store.dispatch('system/getPageListAction', {
pageName: props.pageName,
queryInfo:{
offset:0,
size:10
}
})
}
})
1.20、不同页面的数据请求实现(场景应用:初始化请求所有的数据)。(user请求userlist,role请求rolelist)
思路:dispatch传递的不要是固定接口/user/list
,而是页面名称pageName
实现:
1.获取pageUrl
2. 根据pageName的内容,进行switch判断
3. 然后对页面发送请求
4. 再根据传递进来的pageName内容,将数据分别存储到对应的state中
// 在store下的system.ts 的module模块中
actions: {
async getPageListAction({ commit }, payload: any) {
// 1. 获取pageUrl
const pageName = payload.pageName
// 2. 根据pageName的内容,进行switch判断
let pageUrl = ''
switch (pageName) {
case 'users':
pageUrl = 'users/list'
break
case 'role':
pageUrl = 'role/list'
break
}
// console.log(pageUrl)
// 3. 然后对页面发送请求
const pageResult = await getPageListData(pageUrl, payload.queryInfo)
// console.log(pageResult)
// 4. 再根据传递进来的pageName内容,将数据分别存储到对应的state中
const { list, totalCount } = pageResult.data
switch (pageName) {
case 'users':
commit('changeUserList', list)
commit('changeUserCount', totalCount)
break
case 'role':
commit('changeRoleList', list)
commit('changeRoleCount', totalCount)
break
}
},
}
注意:useStore只能在setup里使用,在一般的js/ts文件中没法使用const store = useStore()
。--
src/components/nav-menu.vue
1.8、引入useRouter和useRoute。import { useRouter, useRoute } from 'vue-router'
1.9、实例router实例对象,可以使用router对象的方法,,例如router.push。const router = useRouter()
1.10、实例route实例对象,可以使用当前路由对象的方法,例如route.path。const route = useRoute()
1.17、获取所有的路由对象。console.log(router.getRoutes());
1.18、在导航守卫router.beforeEach
中可以获取即将跳转的route对象。
router.beforeEach((to) => {
if (to.path !== '/login') {
const token = LocalCache.getCache('token')
if (!token) {
return '/login'
}
}
if (to.path === '/main') {
return firstMenu.url
}
// 获取所有的路由对象
// console.log(router.getRoutes());
// to其实就是即将跳转的route对象
// console.log(to);
})
src/views/main.vue
1.11、动态绑定属性+三元运算符。
src/utils/map-menus.ts
1.12、调用数组的高阶方法:forEach,将部分数据添加到另一个数组中。
computed(()=> {})
computed返回值是一个ref对象:const userMenus = computed(() => store.state.login.userMenus)
switch 类似于 if 判断
switch可以根据条件判断,返回不同的值。
应用场景:数据的转换功能
例如:
// 如果pageName是users,执行第一个选项,如果是role,执行第一个选项,
switch (pageName) {
case 'users':
commit('changeUserList', list)
commit('changeUserCount', totalCount)
break
case 'role':
commit('changeRoleList', list)
commit('changeRoleCount', totalCount)
break
}
参考链接:https://www.jb51.net/article/209948.htm
1.13、组件实例中绑定ref
1.14、setup中定义refChart
对应的ref对象
。const refChart = ref();
1.15、通过refChart.value.属性/方法
,可以直接使用。
参考链接:
重要:props和context分别在template和setup中使用说明https://www.jianshu.com/p/6e27bee45dcb
了解:props和context相关名词定义解释https://blog.csdn.net/weixin_48789376/article/details/119174911
1.21、子组件的props,如果是template
中使用,可以直接使用props对象中定义的变量名
1.21、子组件的props,如果是setup
中使用,需要setup(props)
,然后通过props.变量名
,获取对应的属性
注意:props:接收传过来的参数必须先进行声明,如果没声明,传过来的参数将出现在attrs中
1.15、context :上下文意思,包括 attrs 、 emit 、slots。
① attrs :在此部分,接收在父组件传递过来的,并且没有在props中声明的参数参数。
——在template
中使用,这些属性都存储在$attrs对象
中,可以通过{{ $attrs.属性名 }}
获取
——在setup
函数中获取,这些属性都存储在setup函数的第二个参数对象context的attrs属性
中,可以通过context.attrs.属性名
获取
② emit:子组件对父组件发送事件
③ slots:是一个 proxy 对象,其中 slots.default() 获取到的是一个数组,数组长度由组件的插槽决定,数组内是插槽内容。
1.16、context,常见的用法:{ emit }、{attrs}、{slots}
src/components/nav-header.vue
2.1、监听事件。
2.2、监听事件函数。const handleFoldClick = () => {}
2.3、添加emits属性。export default defineComponent({ emits: ['foldChange']})
2.4、setup函数中解构{emit}。setup(props, { emit }) {}
2.5、发出事件函数,可以带参数(isFold.value
是参数)。const handleFoldClick = () => {emit('foldChange', isFold.value)}
src/views/main.vue
2.6、接收发出的事件函数,父组件自定义函数。
2.7、写父组件的监听函数(有参数记得写形参)。const handleFoldChange = (isFold: boolean) => {isCollapse.value = isFold}
2.8、接收参数,修改父组件中定义好的变量。isCollapse.value = isFold
2.9、另一个子组件动态绑定该属性。
src/components/nav-menu.vue
2.10、另一个子组件内设置props属性。export default defineComponent({props: { collapse:Boolean }})
2.11、另一个子组件内可以动态绑定props属性。
src/router/index.ts
2.12、注册not-found路由映射关系
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('@/views/not-found/not-found.vue')
}
src/views/not-found/not-found.vue
2.13、创建not-found组件
原理:登录–账号(角色)–菜单列表–包含url–对应路由的path–对应component
例如:登录–coderwhy–角色管理–包含/main/role–对应路由的path–对应component
实际:登录–coderwhy–N多菜单–菜单中有url–前端提前配置好所有的url和组件的映射–根据菜单中的url加载对应的组件–形成routes数组–动态加载到main路由下的chilren属性中
注意:提前创建好router文件和view文件,并配置好关系
封装调用的逻辑:
1.确认要实现哪个功能,并确认该功能的执行位置
2.估算功能实现的逻辑(要获取什么)
3.将逻辑封装到单独函数文件中,执行封装函数,函数返回值就是要获取的内容
4.案例可结合下面的 2.14,2.15,2.19
// 封装函数的大概流程
export function mapMenusToRoutes(userMenus) {
// 定义一个空的数组类型的返回值
const routes = []
// 中间写代码逻辑
// 1.先去加载默认所有的routes
// 2.根据菜单获取需要添加的routes
// 。。。。
// 返回值
return routes
}
// 调用封装函数
const routes = mapMenusToRoutes(userMenus)
(1)动态注册路由
src/store/login/login.ts
2.14、因为账号登录后可以获取菜单列表,并保存进行保存,所以可以在这里操作动态添加路由
2.15、根据菜单,找到对应的router的路由:userMenus --> routes
2.19、调用封装的map-menus.ts里的mapMenusToRoutes函数。const routes = mapMenusToRoutes(userMenus)
src/utils/map-menus.ts
2.16、先去加载默认所有的routes
2.17、根据菜单获取需要添加的routes
2.18、递归函数
src/store/login/login.ts
2.19、调用封装的map-menus.ts里的mapMenusToRoutes函数,获取的就是待添加的routes数组
2.20、通过routes数组的forEach,动态添加路由router.addRoute('main', route)
(2)实现路径和组件的映射关系
src/components/nav-menu.vue
2.21、在菜单中,添加监听事件
2.22、监听事件中,添加路由映射
src/views/main.vue
2.23、因为是在main路由添加子路由,所以需要在main.vue文件下进行
占位
判断:
router.before
导航守卫中,查看所有的路由对象router.getRoutes()
和即将跳转的路由对象to
是否正确。方案:
app.use(store)
和app.use(router)或者setupStore()
顺序反了。store
,再执行setupStore(),最后执行router
app.use(store)
setupStore()
app.use(router)
原因:
方案:
实现:
const route = useRoute()
和const currentPath = route.path
const menu = pathMapToMenu(userMenus.value, currentPath)
const currentMenuId = ref(menu.id + '')
// data,匹配页面刷新时,菜单项固定某一位置的bug
//Template:
setup() {
const route = useRoute()
const currentPath = route.path
const menu = pathMapToMenu(userMenus.value, currentPath)
const currentMenuId = ref(menu.id + '')
}
原因:
方案:
实现:
let firstMenu = null
// map-menu.ts文件
let firstMenu: any = null
export function mapMenusToRoutes(userMenus) {
// ...中间省略
const _recurseGetRoute = (menus) => {
for (const menu of menus) {
if (menu.type === 2) {
const route = allRoutes.find((route) => route.path === menu.url)
if (route) {
routes.push(route)
}
if (!firstMenu) {
firstMenu = menu
}
} else {
_recurseGetRoute(menu.children)
}}}}
export { firstMenu }
//router/index.ts
router.beforeEach((to) => {
if (to.path !== '/login') {
const token = LocalCache.getCache('token')
if (!token) {
return '/login'
}
}
if (to.path === '/main') {
return firstMenu.url
}})
src/base-ui/from/src/form.vue
3.1、修改UI组件的样式,以ElementPlus为例。
3.2、v-bind绑定对象,是将对象内的所有属性全部动态绑定到组件中。
3.3、props中变量如果是数组
或者对象
类型,需要将default
写成函数
的形式。formItems: { type: Array, default: () => [] },
3.4、逻辑运算符(逻辑与&&、逻辑或||)的使用。
3.5、动态获取数据的另一种方式v-model=“formData[`${item.field}`]”
参考链接: https://www.cnblogs.com/guanghe/p/11157201.html?ivk_sa=1024320u
(1)当出现在条件判断语句中时,例如 i f 语句,返回值Boolean
1.&&
1.1两边条件都为true时,结果才为true;
1.2如果有一个为false,结果就为false;
1.3当第一个条件为false时,就不再判断后面的条件
注意:当数值参与逻辑与运算时,结果为true,那么会返回的会是第二个为真的值;如果结果为false,返回的会是第一个为假的值。
2.||
2.1只要有一个条件为true时,结果就为true;
2.2当两个条件都为false时,结果才为false;
2.3当一个条件为true时,后面的条件不再判断
注意:当数值参与逻辑或运算时,结果为true,会返回第一个为真的值;如果结果为false,会返回第二个为假的值;
(2)当出现在赋值语句中时,例如变量赋值、return结果等,返回值是其中一方的运算结果,会遵循以下规则:
const result = 表达式a && 表达式b :
result的运算结果,
先判断计算表达式a(也可以是函数)的运算结果,
如果为 True, 执行表达式b(或函数),并返回b的结果;
如果为 False,返回a的结果;
const result = 表达式a || 表达式b :
result的运算结果,
先判断计算表达式a(也可以是函数)的运算结果,
如果为 Fasle, 执行表达式b(或函数),并返回b的结果;
如果为 True,返回a的结果;
v-bind:属性=‘变量’
或者v-bind=‘对象’
v-bind=‘对象’
的方式将配置对象动态绑定到组件中。// form.vue
<template>
<div class="hy-form">
<el-form>
<template v-for="item in formItems" :key="item.label">
<el-form-item :label="item.label" :style="itemStyle">
<template v-if="item.type === 'input' || item.type === 'password'">
<el-input :show-password="item.type === 'password'" />
</template>
</el-form-item>
</template>
</el-form>
</div>
</template>
<script>
export default {
props: {
formItems: {
type: Array,
default: () => ([])
},
itemStyle: {
type: Object,
default: () => ({ padding: '10px 40px' })
},
setup() {return {}}
}
</script>
// user.vue
<template>
<div class="user">
// 进阶
<hy-form
:formItems="formItems"
:itemStyle="itemStyle"
/>
</div>
</template>
<script>
import HyForm from '@/base-ui/form'
// import { searchFormConfig } from './config/search.config' 进阶
// 将setup中itemStyle和formItems 属性抽到search.config.js文件中,保存成对象格式。再导入进来
export default {
name: 'user',
components: {
HyForm
},
setup() {
const itemStyle= {
padding: '10px 40px'
}
const formItems = [
{
type: 'input',
label: '用户名',
placeholder: '请输入用户名'
},
{
type: 'password',
label: '密码',
placeholder: '请输入密码'
}]
return {
formItems,
itemStyle,
// searchFormConfig 进阶
}
}
}
</script>
1.基础:
所有的表单(例如input表单)都有v-model="name"
的属性,通过v-model可以将在input输入的内容,放入到v-model绑定的name
属性中。
2.封装:
2.1 在外部引入的文件中,定义一个formData数据
2.2 在自定义组件上,动态绑定formData数据
2.3 在封装组件文件中,使用props接收formData数据
3.如果只有一个表单:
3.1 在封装组件文件v-model直接绑定接收的formData数据既可以了。
4.如果有多个表单,如何实现一一对应的关系:
4.1 通过在formItem
属性中,添加一个field
字段。
4.2 该field
字段名称要与formData
中定义的属性名保持一致。
4.3 在封装组件文件中,通过
4.4 如果有eslint报错,在eslintrc.js中关闭检测即可
<el-input v-model="name" />
<template>
<div class="user">
//<hy-form v-bind="searchFormConfig" :formData='formData' /> 进阶
<hy-form
:formItems="formItems"
:itemStyle="itemStyle"
/>
div>
template>
<script>
import HyForm from '@/base-ui/form'
// import { searchFormConfig } from './config/search.config' 进阶
// 将setup中itemStyle和formItems 属性抽到search.config.js文件中,保存成对象格式。再导入进来
export default {
name: 'user',
components: {
HyForm
},
setup() {
const itemStyle= {
padding: '10px 40px'
}
const formItems = [
{
field:'name',
type: 'input',
label: '用户名',
placeholder: '请输入用户名'
},
{
field:'password',
type: 'password',
label: '密码',
placeholder: '请输入密码'
}]
const formData = ref({
name:'',
password:''
})
return {
formItems,
itemStyle,
formData,
// searchFormConfig 进阶
}
}
}
script>
<template>
<div class="hy-form">
<el-form>
<template v-for="item in formItems" :key="item.label">
<el-form-item :label="item.label" :style="itemStyle">
<template v-if="item.type === 'input' || item.type === 'password'">
<el-input :show-password="item.type === 'password'" v-model="formData[`${field}`]" />
template>
el-form-item>
template>
el-form>
div>
template>
<script>
export default {
props: {
formItems: {
type: Array,
default: () => ([])
},
itemStyle: {
type: Object,
default: () => ({ padding: '10px 40px' })
},
formData: {
type: Object,
required:true
}
setup() {return {}}
}
script>
1.基础使用
定义插槽
<template>
<div class="msz-form">
<div class="header">
<slot name="header">slot>
div>
<el-form :label-width="labelWidth">
el-form>
div>
template>
使用插槽
<template>
<div class="page-search">
<msz-form v-bind="searchFormConfig" v-model="formData">
<template #header>
<h1 class="header">高级检索h1>
template>
msz-form>
div>
template>
可以参考【后台管理系统项目实战(八)–04_(掌握)HyForm实现双向绑定的方案】
|-- service
| |-- index.ts
| |-- main
| | |-- system
| | |-- system.ts
| |-- request
| |-- config.ts
| |-- index.ts
|-- store
| |-- index.ts
| |-- main
| |-- system
| |-- system.ts
|-- views
|-- main
| |-- system
| |-- user
| |-- user.vue
<template>
//省略了结构内容
</template>
<script>
import { defineComponent, computed } from 'vue'
import { useStore } from 'store'
export default defineComponent({
name: 'user',
setup() {
const store = useStore()
// 简单的方式:参数写死,
// pageUrl:接口的URL,可以直接写死省事
// queryInfo:接口查询的条件,有哪些写哪些
store.dispatch('system/getPageListAction', {
pageUrl: '/users/list',
queryInfo: {
offset: 0,
size: 10
}
})
import { createStore} from 'vuex'
import system from './main/system/system'
const store = createStore({
state() {
return {
name: 'coderwhy',
age: 18
}
},
mutations: {},
getters: {},
actions: {},
modules: {
system
}
})
// 加载本地缓存数据的
export function setupStore() {
store.dispatch('login/loadLocalLogin')
}
export default store
import { Module } from 'vuex'
import { getPageListData } from '@/service/main/system/system'
const systemModule = {
// 命名空间
namespaced: true,
state() {
return {
userList: [],
userCount: 0
}
},
mutations: {
changeUserList(state, userList: any[]) {
state.userList = userList
},
changeUserCount(state, userCount: number) {
state.userCount = userCount
}
},
actions: {
async getPageListAction({ commit }, payload) {
// 打印看下是否可以获取到查询条件
console.log(payload.pageUrl)
console.log(payload.queryInfo)
// 1.对页面发送请求,调用的是service下的请求
const pageResult = await getPageListData(
payload.pageUrl,
payload.queryInfo
)
// 获取到list和totalCount 数据
const { list, totalCount } = pageResult.data
// 提交commit保存到state中
commit('changeUserList', list)
commit('changeUserCount', totalCount)
}
}
}
export default systemModule
import hyRequest from '../../index'
export function getPageListData(url: string, queryInfo: any) {
return hyRequest.post<IDataType>({
url: url,
data: queryInfo
})
}
<template>
<div class="user">
<hy-table :listData="userList" :propList="propList">
// 中间代码省略
</hy-table>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useStore } from 'store'
import HyTable from '@/base-ui/table'
export default defineComponent({
name: 'user',
components: {
HyTable
},
setup() {
const store = useStore()
// 提交请求
store.dispatch('system/getPageListAction', {
pageUrl: '/users/list',
queryInfo: {
offset: 0,
size: 10
}
})
// 获取store中的数据,通过computed来监听,实时改变
const userList = computed(() => store.state.system.userList)
const userCount = computed(() => store.state.system.userCount)
return {
userList,
}
}
})
</script>
<style scoped></style>
<template>
<div class="user">
<div class="content">
<el-table :data="userList " border style="width: 100%">
<template v-for="propItem in propList" :key="propItem.prop">
<el-table-column v-bind="propItem" align="center"></el-table-column>
</template>
</el-table>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useStore } from '@/store'
export default defineComponent({
name: 'user',
setup() {
const store = useStore()
store.dispatch('system/getPageListAction', {
pageUrl: '/users/list',
queryInfo: {
offset: 0,
size: 10
}
})
const userList = computed(() => store.state.system.userList)
const userCount = computed(() => store.state.system.userCount)
const propList = [
{ prop: 'name', label: '用户名', minWidth: '100' },
{ prop: 'realname', label: '真实姓名', minWidth: '100' },
{ prop: 'cellphone', label: '手机号码', minWidth: '100' },
{ prop: 'enable', label: '状态', minWidth: '100', slotName: 'status' },
{
prop: 'createAt',
label: '创建时间',
minWidth: '250',
slotName: 'createAt'
},
{
prop: 'updateAt',
label: '更新时间',
minWidth: '250',
slotName: 'updateAt'
}
]
return {
userList,
propList
}
}
})
</script>
<style scoped>
.content {
padding: 20px;
border-top: 20px solid #f5f5f5;
}
</style>
可以参考【后台管理系统项目实战(八)–08_(掌握)HyTable的动态插槽和作用域插槽】
<template>
<div class="hy-table">
<el-table :data="listData" border style="width: 100%">
<template v-for="propItem in propList" :key="propItem.prop">
<el-table-column v-bind="propItem" align="center">
<template #default="scope">
<slot :name="propItem.slotName" :row="scope.row">
{{ scope.row[propItem.prop] }}
slot>
template>
el-table-column>
template>
el-table>
div>
template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
listData: {
type: Array,
required: true
},
propList: {
type: Array,
required: true
}
},
setup() {
return {}
}
})
script>
<style scoped>style>
<template>
<div class="user">
<page-search :searchFormConfig="searchFormConfig" />
<div class="content">
<hy-table :listData="userList" :propList="propList">
<template #status="scope">
<el-button>{{ scope.row.enable ? '启用' : '禁用' }}el-button>
template>
<template #createAt="scope">
<strong>{{ scope.row.createAt }}strong>
template>
hy-table>
div>
div>
template>
<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useStore } from '@/store'
import PageSearch from '@/components/page-search'
import HyTable from '@/base-ui/table'
import { searchFormConfig } from './config/search.config'
export default defineComponent({
name: 'user',
components: {
PageSearch,
HyTable
},
setup() {
const store = useStore()
store.dispatch('system/getPageListAction', {
pageUrl: '/users/list',
queryInfo: {
offset: 0,
size: 10
}
})
const userList = computed(() => store.state.system.userList)
const userCount = computed(() => store.state.system.userCount)
const propList = [
{ prop: 'name', label: '用户名', minWidth: '100' },
{ prop: 'realname', label: '真实姓名', minWidth: '100' },
{ prop: 'cellphone', label: '手机号码', minWidth: '100' },
{ prop: 'enable', label: '状态', minWidth: '100', slotName: 'status' },
{
prop: 'createAt',
label: '创建时间',
minWidth: '250',
slotName: 'createAt'
},
{
prop: 'updateAt',
label: '更新时间',
minWidth: '250',
slotName: 'updateAt'
}
]
return {
searchFormConfig,
userList,
propList
}
}
})
script>
<style scoped>
.content {
padding: 20px;
border-top: 20px solid #f5f5f5;
}
style>
<template #createAt="scope">
<span>{{ formatTime(scope.row.createAt) }}</span>
</template>
<script>
const formatTime = ()=>{...省略}
</script>
// 根文件main.js
// 在全局注册了一个$filter的函数,后期在任何地方都可以通过$filter()使用该函数
// $filter:是自定义的函数名
app.config.globalProperties.$filter = function() {
// 代码逻辑写在这
return '返回结果'
}
// 绑定一个对象
app.config.globalProperties.$filter = {
foo(){
// foo函数的代码逻辑写在这
return '返回结果'
},
formatTime(){
// formatTime函数的代码逻辑写在这
return '返回结果'
}
}
// 在template中使用
<template #createAt="scope">
<span>{{ $filter.formatTime(scope.row.createAt) }}span>
template>
// main.js
// 导入
import push from '@/utils/push'
import api from '@/utils/api'
// 中间忽略了const app = createApp(App)等代码
// 绑定
app.config.globalProperties.$asyncPost = api.nextPost
app.config.globalProperties.$push = push
// 在setup中使用
<script>
import { getCurrentInstance } from 'vue'
export default {
setup() {
const instance = getCurrentInstance()
console.log('instance是:', instance.appContext.config.globalProperties)
return {}
},
}
</script>
import dayjs from 'dayjs'
// 导入utc才可以支持对utc转化
import utc from 'dayjs/plugin/utc'
// 使用utc
dayjs.extend(utc)
// 时间格式化:默认样式
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
// UTC时间格式化
export function formatUtcString(
utcString: string,
format: string = DATE_TIME_FORMAT
) {
// 时间偏移8小时:utcOffset(8)
return dayjs.utc(utcString).utcOffset(8).format(format)
}
// 时间戳时间格式化
export function formatTimeStamp(
timeStamp: number,
format: string = DATE_TIME_FORMAT
) {
if (Number.isInteger(timeStamp)) {
if (timeStamp.toString().length === 13) {
// 毫秒
return dayjs(timeStamp).format(format)
} else if (timeStamp.toString().length === 10) {
// 秒
return dayjs(timeStamp).format(format)
}
}
}
第一层:最终的页面需求页面
User.vue:
1.引用第二层的封装组件
2.数据通过props/emits传递
3.网络请求可以通过Vuex进行发出
第二层:代码逻辑页面
Search.vue:
1.实现业务的逻辑代码
2.可以与User.vue通过props/emits传递数据
如果其他页面也有类似的组件需求:
1.可以通过复制当前 的组件,适当修改
2.扩展当前组件的复用性
第一层:最终的页面需求页面
User.vue:
1.引用封装好的第二层的封装文件
2.引用封装好的第二层的配置文件
3.将配置文件和组件进行绑定
第二层:中间过渡层
PageContent.vue:
1.引用封装好的第三层的封装文件
2.通过props/emit实现与第一层和第三层的传递
3.与Vuex打通,实现数据状态管理
4.网络请求发送,在这层实现
5.补充并彻底实现第一层的需求
第三层:代码逻辑页面
maSZtable.vue:
1.实现业务的逻辑代码
2.通过props/emit实现与第二层的传递
// page-search.vue
// 监听事件
<template>
<div class="page-search">
<msz-form v-bind="searchFormConfig" v-model="formData">
<template #header>
<h1 class="header">高级检索</h1>
</template>
<template #footer>
<div class="handle-btns">
<el-button @click="handleResetClick">重置</el-button>
<el-button type="primary" @click="handleQueryClick">搜索</el-button>
</div>
</template>
</msz-form>
</div>
</template>
<script lang="ts">
setup(props, { emit }) {
const formDataInt = ref({
id: '',
name: '',
password: '',
sport: '',
createTime: ''
}),
const formData = ref({
id: '',
name: '',
password: '',
sport: '',
createTime: ''
})
// 当用户点击重置,进行数据重置
const handleResetClick = () => {
// 数据重置
// 因为这是个input表单,不会有数据的产生
formData.value = formDataInt.value
// 重新发送查询请求
emit('resetBtnClick')
}
}
</script>
// user.vue
<template>
<div class="user">
// 接收事件
<page-search @resetBtnClick="handleResetBtnClick"></page-search>
<page-content ref="pageContentRef"></page-content>
</div>
</template>
<script lang="ts">
export default defineComponent({
setup() {
// 处理事件
const handleResetBtnClick = () => {
// 获取PageContentRef,调用查询数据的方法
pageContentRef.value?.getPageData()
}
return {
handleResetBtnClick,
}
}
})
</script>
<template>
<div class="page-content">
<msz-table :listData="dateList" :listCount="dataCount">
</msz-table>
</div>
</template>
<script lang="ts">
export default defineComponent({
setup() {
// 1.发送网络请求
const getPageData = (queryInfo: any = {}) => {
// 发送网络前,判断是否有对应权限
// 没有权限
if (!isQuery) return
// 有权限
store.dispatch('system/getPageListAction', {
pageName: props.pageName,
queryInfo: {
offset: (pageInfo.value.currentPage - 1) * pageInfo.value.pageSize,
size: pageInfo.value.pageSize,
...queryInfo
}
})
}
// 2.调用发送网络请求 的函数
getPageData()
// 3.从Vuex中获取数据
const dateList = computed(() => {
return store.getters[`system/pageListDate`](props.pageName)
})
const dataCount = computed(() => {
return store.getters[`system/pageListCount`](props.pageName)
})
return {
dateList,
dataCount
}
}
})
</script>
// page-search.vue
// 监听事件
<template>
<div class="page-search">
<msz-form v-bind="searchFormConfig" v-model="formData">
<template #header>
<h1 class="header">高级检索</h1>
</template>
<template #footer>
<div class="handle-btns">
<el-button @click="handleResetClick">重置</el-button>
<el-button type="primary" @click="handleQueryClick">搜索</el-button>
</div>
</template>
</msz-form>
</div>
</template>
<script lang="ts">
setup(props, { emit }) {
// 当用户点击搜索
const handleQueryClick = () => {
// formData.value就是查询条件
emit('queryBtnClick', formData.value)
}
}
</script>
// user.vue
<template>
<div class="user">
// 接收事件
<page-search @queryBtnClick="handleQueryBtnClick"></page-search>
<page-content ref="pageContentRef"></page-content>
</div>
</template>
<script lang="ts">
export default defineComponent({
setup() {
// 处理事件
const handleQueryBtnClick = (queryInfo) => {
// 获取PageContentRef,调用查询数据的方法,传递参数,把formData.value传递到queryInfo中
pageContentRef.value?.getPageData(queryInfo)
}
return {
handleQueryBtnClick ,
}
}
})
</script>
<template>
<div class="page-content">
<msz-table :listData="dateList" :listCount="dataCount">
</msz-table>
</div>
</template>
<script lang="ts">
export default defineComponent({
setup() {
// 1.发送网络请求,formData.value传递到queryInfo
const getPageData = (queryInfo: any = {}) => {
// 发送网络前,判断是否有对应权限
// 没有权限
if (!isQuery) return
// 有权限
store.dispatch('system/getPageListAction', {
pageName: props.pageName,
queryInfo: {
offset: (pageInfo.value.currentPage - 1) * pageInfo.value.pageSize,
size: pageInfo.value.pageSize,
// 将formData.value解构,作为查询条件进行传递
...queryInfo
}
})
}
// 2.调用发送网络请求 的函数
getPageData()
// 3.从Vuex中获取数据
const dateList = computed(() => {
return store.getters[`system/pageListDate`](props.pageName)
})
const dataCount = computed(() => {
return store.getters[`system/pageListCount`](props.pageName)
})
return {
dateList,
dataCount
}
}
})
</script>
还有个登录模块的内容没有弄,因为现在也没做,等后续需要了看看在说。