166
请求工具架构搭建相关:
- 将与请求相关(和 axios 相关)的配置封装成一个模块,此模块包含创建 axios 实例、请求拦截器和响应拦截器这三个核心部分。
- 先在 VS Code 中操作,第一步是装包(如通过 PNPM add 安装 axios),对于 axios 的配置,可从官网的 create instance 部分获取已有内容,将其复制到新建的utils下的request.js 文件中。实例最终要默认导出,baseURL 可按需导出。
具体配置内容:
- 基础地址和超时时间配置:在 request.js 文件中,设置基础地址(如写 baseURL),超时时间可设为 10 秒钟等。
- 请求拦截器配置:
- 需要在请求中携带 token,token信息存储在 piana仓库中,从统一出口(如 @ stores)导入useUserStore相关方法来获取仓库数据。具体是使用 use user store 导出,在需要用数据的地方通过 const useStore = useUserStore调用,判断userStore里的 token 是否存在,若存在则往请求头(config.headers)携带,根据接口文档,请求头字段名为 Authorization,其值为 useStore 里的 token。
- 响应拦截器配置:
- 成功情况:当后台返回数据的状态码 code 为 0 时代表成功,此时直接返回原本内容(return res)。
- 失败情况:若 code 不为 0 则代表业务失败,需给用户提示并抛出错误,可通过 return promise.reject (res.data) 抛出错误信息结果。还可利用 element plus 中的消息提示框(import from element plus 找到 ElMessage,通过ElMessage.error 给错误提示),错误提示优先以接口文档中的 message 为准,若没有则根据情况给服务器繁忙等提示。
- 401 错误特殊情况:若状态码为 401,说明权限不足或 token 过期,此时应拦截到登录,通过判断当前 err.response?.status 里的状态码是否等于 401,若是则调 router.push 进行相关处理(先通过 import router from '@/router' 导入 router)。
167
分析页面并规划路由:登录注册共用一级路由,首页的左侧架子和头部为一级路由,架子内的文章分类、文章管理、个人中心为二级路由
创建组件:在 views 文件夹中创建相应的路由组件,如登录页、架子、文章管理等
配置路由规则:在 router下的 index.js 文件中配置路由规则,包括登录页和架子的路由,以及文章管理等子路由的路由
添加路由出口:在 APP.vue 文件中添加路由出口,将匹配到的路由渲染到相应的组件中
168
实现登录页面的布局结构:利用 el-row 和 el-column 组件进行布局,一行分为 24 份,左边占 12 份,通过设置 el-column 的 span 属性为 12 实现。右边核心模块占 6 份,同时设置 offset 为 3,使得右边内容在一行中居中显示
登录页表单部分:整体由el-form 包裹,每一行是el-form-item,可理解为一个表单域,互相独立。表单元素通常有el-input
169
注册功能添加校验需理解四个核心要点:
- :model 绑定 form 对象,用于收集表单数据,通过一个对象维护表单数据方便校验、重置和提交。
- :rules绑定规则对象,在其中为每个表单数据配置校验规则。
- v- model 绑定 form 的子属性,实现表单元素与 form 的双向绑定
- prop 配置生效的校验规则,与 rules 中的字段对应
具体操作:
- 准备 form 对象,根据接口文档提供注册相关字段(username、password、repassword)。
- 为el-form 绑定 form 对象和校验规则对象,在规则对象中为每个字段配置非空校验、长度校验和正则校验。
- 为表单元素绑定 form 的子属性,并配置 prop
自定义校验:
- 在 rules中为 repassword 字段配置自定义校验,设置 validator属性,并编写一个校验函数,包括非空校验和与 password 一致的校验。
- 在自定义校验函数中,根据 value( 所校验的表单元素目前的表单值)和 callback(回调函数) 配置校验逻辑,无论成功失败都要调用 callback,当
value
不满足条件时,通过callback(new Error('错误信息'))
给出错误提示;当value
满足条件时,直接callback()
表示校验成功 - 为表单元素绑定 form 的子属性,并配置 prop 和 trigger
170
注册预校验
- 预校验原理
在正式注册提交之前需进行预校验,点击注册按钮时对当前表单内容校验,通过校验才进行提交请求。这需要调用 element plus 中 form 表单的方法,通过 form expose 可找到暴露的方法。在 Vue 3 中,若组件内部不对外暴露方法则无法调用,此处已暴露可直接用 validator 方法进行整个表单的验证,它会返回一个 promise。 - 获取 form 组件实例
在 Vue 3 中要拿到当前 form 组件实例需添加 form ref。代码中两个登录和注册表单都添加了 ref 绑定,虽两个 ref 同名,但因使用了 v - if,同时只有一个元素在页面,所以不会冲突。 - 注册按钮点击事件及校验处理
为注册按钮添加点击事件 register,在方法中通过 await form.value.validate () 等待验证结果。若等待成功则进行注册请求,若失败则 validator 方法会触发校验并自动显示错误提示,只需处理校验成功的情况。
注册接口封装与调用
- 接口封装
根据接口文档,注册请求是 post 方式,地址是 API 下的 register,参数在 body 传递。在 VS code 中选择 API 模块新建 user.js 文件,导入 request 方法,按规范定义 userRegisterService 方法。 - 接口调用及页面交互
在页面中导入 userRegisterService 方法,调用时将 formModel 中的 username、password 和 repassword(都要带.value)传过去。成功后 ElMessage.success提示 “注册成功”
171
登录功能实现步骤
1. 表单相关配置与校验
- 共用数据与规则:注册和登录可共用 formModel 数据,因为都是 username 和 password 字段。在登录部分,先进行 form 与 formModel 的绑定,然后配置规则,直接使用已定义好的 rules 。在各输入框处通过 v-model 绑定对应的 formModel 里的字段,像 username 和 password ,并且在每个 <el-form-item> 上添加 prop 属性对应好相应字段,进行基本校验,不过登录没有确认密码字段。
- 解决表单数据切换残留问题:发现表单在切换(注册与登录切换)时,输入框原有信息会被带到另一处,不合理,需要在切换时重置表单内容。使用 watch 监视 isRegister 变量,当它发生变化时,将 formModel.value 重置为初始状态(各字段为空值),也可根据切换到注册或登录的不同情况分别写判断来重置相应表单内容,经测试可解决数据残留问题,完成基本校验。
2. 登录按钮点击事件与预校验
- 添加点击事件及预校验逻辑:给登录按钮添加点击事件 login ,其预校验逻辑与注册前的预校验一致,通过 await form.value.validate() 在登录请求前进行预校验,前提是 form 表单已绑定好 ref ,这样能保证校验生效,未通过校验则不会发起请求。
3. 登录接口封装与调用
- 接口封装:根据接口文档,登录请求方式为 post ,地址及请求参数确定后,按规范在代码中封装登录接口。在 user.js 文件中,定义 userLoginService 方法,传入 username 和 password 作为参数,调用 request.post 发起请求,例如 export const userLoginService = () => request.post('/API/login', { username, password }); 。
- 接口调用及后续处理:在页面中调用 userLoginService 方法,将 formModel 里的值传进去,等待登录结果,登录成功会返回 token 。获取到 token 后,使用 useUserStore 方法(从 stores/index.js 中导入)拿到用户仓库实例,调用仓库里的 setToken 方法把 token 存起来,例如 userStore.setToken(res.data.token); 。同时因为配置了持久化插件,token 不仅会存到 pinon 中,本地的 localStorage 里也会存储成功。可添加提示信息如 ElMessage.success('登录成功'); 告知用户登录成功,最后还可通过 router.push('/') (先获取 router 实例 const router = useRouter(); )跳转到首页。
172
一、首页相关模块及路由搭建
完成登录后进入首页,需处理文章分类、文章管理、个人中心三大模块,这些模块涉及二级嵌套路由,要先搭建 layout 对应的一级路由架子,会用到 element plus 中的菜单组件,还会涉及登录访问拦截、用户个人信息获取渲染及退出等四大功能模块。
先进行基本架子的拆解,将首页 let out 架子部分的结构代码放入 VS code 里的 layout 中,运行后可看到首页搭建好的架子且能实现路由切换。整体布局用到一些小的布局容器,如 ER container、el aside、ER header 等,可将其类比为有更强语义的 DIV。重点在于理解菜单组件,即 ER menu,其有相关配置项。
二、菜单组件剖析
配置项功能:
active text color:激活时文字的颜色设置,如设为 “FF0000” 则为红色。
background color:背景颜色配置。
default active:配置默认高亮的菜单项,配合 router 选项,router 选项开启后,其值与 el menu item 的 index(跳转路径)相等时菜单项会高亮。
添加菜单项:可直接往底下添加 el menu item,能配置图标和文字,index 配置访问的跳转路径,通过示例演示了 index 用于跳转、default active 用于实现高亮的作用。
多级菜单:介绍了二级菜单,有 template 作为标题,展开内容部分通过具名插槽(如 #title)配置多级菜单的大标题,通过默认插槽配置展开的二级内容,若要添加二级嵌套菜单,可复制相关代码段进行修改。
三、登录访问拦截
拦截必要性:首页内容需登录过的用户才能访问,未登录用户只能访问登录页,否则不合理,所以要做登录访问拦截。
拦截实现位置及语法变化:以前在 root index.js 里添加,此次在 view 3 中同样位置添加,但语法有变化。以前是 “to from next”,现在是 “to from” 且通过返回值判断,不再有 next。
返回值情况及作用:
返回 undefined 或 to 时直接放行。
返回具体路径(如 return force)会回到 from 地址页面。
返回如 “logging in” 等登录页相关内容会将用户重定向到登录页面。
具体拦截逻辑:导入 user store 相关方法获取 token,判断若不存在 token 且访问非登录页则进行拦截,将用户重定向到登录页,其他情况默认放行。实现思路与 view 2 中的登录访问拦截一致,但前置守卫语法发生变化,通过返回值判断放行或拦截。
173
一、用户基本信息获取与渲染
接口封装
- 依据接口文档进行操作:在 VS code 的 api下的user.js 里创建新方法,以此实现获取用户基本信息的接口封装。
- 具体封装示例:export const userGetInfoService = () => request.get('/my/userinfo')。需要注意的是,此接口请求需要携带之前已经配置好的 token。
数据存储与获取
- 在 store 中定义数据:在 store 下的 model/user.js 中定义数据,如
const user = ref({})
。 - 获取数据并存入:通过
getUser
方法发送请求获取数据,getUser
方法为异步函数,其实现为const res = await userGetInfoService() user.value = res.data.data - 数据暴露:将
user
和getUser
暴露出去,方便后续使用。
页面调用与渲染
- 页面导入与方法获取:在页面(比如 layout)中导入 userStore,通过useUserStore获取
getUser
方法。 - 获取数据时机:可以在页面加载阶段(如
created
或mounted
)调用getUser
方法获取最新数据,并将其存入user
对象。 - 渲染规则:渲染用户名时,优先显示
user store.user.nickname
,若不存在则显示user store.user.username
;头像渲染通过user store.user.
pic进行,若没有则使用默认头像。
二、退出功能实现
下拉菜单及路由跳转
- 下拉菜单使用:在 element plus 中有下拉菜单组件,它可以将动作或菜单折叠在其中。
- 操作监听实现:通过给每个菜单项添加
command
标识来实现对不同操作的监听。例如,点击菜单项会触发事件,在handlecommand
函数中能根据command
参数判断操作类型。 - 路由跳转配置:配置的菜单项(如
profile
、avatar
、password
)与对应的路由名字统一,以此实现路由跳转功能(通过root.push
方法)。
退出操作处理
- 退出操作内容:退出操作不仅要跳转到登录页(通过
root.push('/login')
实现),还需要清除本地数据,包括 token 和 user 信息。 - 用户信息重置方法:提供
set user
方法用于重置用户信息,例如const set user = (obj) => { user.value = obj; }
,调用此方法并传入空对象即可重置用户信息。 - 退出时数据处理:在退出操作中,先通过 user store 调用相关方法清除 token(如
user store.remove token
),并将用户设置为空对象(如user store.set user({})
)。
添加确认框
- 确认框使用:使用 element plus 中的
messagebox
消息弹出框添加确认提示。 - 确认框配置内容:配置
confirm
参数,包括提示内容(如 “你确认要进行退出吗?”)、标题(如 “温馨提示”)、类型(如 “warning”)以及确认和取消按钮文本等。 - 操作等待:整个操作会返回一个 promise,可以通过
await
等待确认操作完成后再执行后续的代码。
174
1. 文章分类架子搭建
使用 Element Plus 的 Card 组件
- 引入组件:在 VS Code 中引入 Element Plus 的 Card 组件,它是构建页面基本结构的重要元素。
- 创建卡片容器:运用
<el-card>
标签构建出一个卡片容器,后续文章分类相关的所有内容都会放置在此容器内。
头部和内容的定制
- 头部定义:借助
<template #header>
来自定义 Card 组件的头部。添加了名为page-contains
的类,同时设置标题为 “文章分类”。还添加了一个 “添加分类” 的按钮,该按钮使用 Element Plus 的 Button 组件,并将其类型设定为primary
。 - 内容占位:在 Card 组件的默认插槽里添加了几个 DIV 元素作为内容占位符,后续会用实际的文章分类数据替换它们。
2. 样式设置
基本样式
- 类样式设置:针对
page-contains
类进行样式设定,明确了最小高度、内边距、外边距以及盒模型的边界框大小等样式属性,以此保障组件布局与外观能符合要求。 - 头部布局样式:运用 CSS 的
flex
布局对头部进行样式处理,让标题和按钮在头部能够实现水平与垂直方向上的居中显示。
3. 组件复用
迁移至 components 目录
- 提高复用性举措:为增强代码复用性,把文章分类的架子迁移至
components
目录下,并创建了名为page-content
的新组件。 - 组件复用方式:该组件通过
props
接收标题,如此一来,在不同页面使用时,只需传入不同标题就能实现复用。
插槽的使用
- 默认插槽运用:利用默认插槽来填充组件的主要内容,方便在不同页面插入不一样的内容。
- 具名插槽使用:借助具名插槽
action
来定制头部右侧的按钮,不同页面可依据自身需求添加相应按钮。
4. 文章分类核心功能
渲染
- 功能实现:成功实现文章分类的渲染功能,通过发送 ABI 请求获取相关数据,然后将数据展示在页面上。
- 用户体验优化:添加了
loading
效果,在数据加载过程中显示加载指示器,以此提升用户使用体验。
添加和编辑
- 组件封装:封装了一个弹层组件用于添加和编辑分类,此组件具备复用性,能有效减少代码重复编写的情况。
删除
- 删除功能实现:实现了删除功能,用户可以把不需要的分类删除掉,并且在删除成功后能自动更新页面显示内容。
5. 页面使用组件
快速实现页面
- 定制标题:在不同页面使用
page-content
组件时,可通过传递title
属性来定制符合页面需求的标题。 - 内容插入:借助默认插槽插入主要内容,比如插入表格等元素。
- 按钮添加:若需要在头部添加按钮,则可以通过具名插槽
action
来达成目的。
6. 自动注册组件
按需引入
利用 Vue 的按需引入机制,使得components
目录下的组件能够自动注册,这样就无需在每个页面中手动去进行组件注册操作了。
175
二、添加和编辑功能中弹层处理的关联性
在文章分类的添加和编辑操作中,当点击添加或编辑按钮时,都会触发显示 element plus 的弹层。这个弹层的展示逻辑、数据校验等方面具有共性,这为将二者放在一起实现提供了依据。通过这种方式,可以避免代码的重复编写,提高代码的可维护性和可读性。
三、element plus 弹层的展示原理与实现步骤
- 依据官方文档配置弹层
- 查找官方文档信息:首先需要参考 element plus 的官方文档。通过在文档中搜索 “dialogue”,可以找到 dialog 对话框相关内容。这个对话框的文档页面中包含了详细的使用说明,其中有一个查看源代码的按钮,这是关键入口。
- 分析弹层渲染原理:在源代码相关内容中,发现只需将一个特定的布尔值修改为 true,就可以实现页面中 dialogue 的渲染。这表明了弹层的显示与否是由这个布尔值控制的。
- 确定弹层配置参数:以 Vega model 为例,它绑定了一个布尔值,同时还有其他参数。例如,title 用于配置弹层的标题,width 用于指定弹层的宽度(如设置为 30%)。此外,还有 before close 相关的设置,它规定了在关闭弹层之前需要执行的操作。但在当前场景下,不需要这个 before close 相关的功能,所以只保留前三部分内容以及底下的 span 和 future 相关部分,然后将这部分代码复制到 VS code 中,以便后续在项目中使用。
- 在项目中添加弹层并设置相关变量
- 确定弹层添加位置:弹层需要添加到 article channel 部分。在实际操作中,先在 table 下面添加弹层,后续还会对其进行进一步的封装和优化。
- 设置弹层显示控制变量:添加一个名为 dialogue visible 的变量,初始值设置为 false,这意味着弹层默认是隐藏状态。这样的设置符合用户交互的逻辑,只有在用户触发添加或编辑操作时,弹层才会显示。
- 配置弹层内容和按钮功能:对于弹层的标题,可以根据实际需求设置,比如 “添加分类”。弹层内部的内容部分可以根据具体的业务逻辑来填充,这里只是简单示例为 “this is message”。在弹层的底部,通过 template foot 来配置按钮。在这个区域创建了一个取消按钮,当用户点击取消按钮时,将 dialogue visible 的值设置为 false,实现关闭弹层的功能。同时,还创建了一个确认按钮,点击确认按钮时也将 dialogue visible 的值修改为 false(这里可能存在一些特殊情况,后续可能需要根据具体的业务逻辑来进一步调整确认按钮的功能)。
四、弹层复用的实现与组件封装
- 弹层复用的必要性与思路
由于添加和编辑操作都需要使用弹层,为了提高代码的复用性和可维护性,决定将弹层封装成一个通用的组件。这样,在不同的操作中都可以调用这个组件来显示弹层,避免了重复编写相似的代码。 - 创建并配置 channel edit 组件
- 创建组件文件:在 article 文件夹下新建一个 components 文件夹,这个文件夹专门用于存放当前模块下的小组件。在这个新创建的文件夹中新建一个名为 channel edit 的组件。这种目录结构的设计可以提高项目的可阅读性,使代码的组织更加清晰,各个模块之间的关系更加明确。
- 迁移弹层相关代码和变量:将之前在 article channel 中实现的整个 dialog 相关的代码部分剪切并粘贴到新创建的 channel edit 组件中。这包括弹层的配置代码、显示控制变量 dialogue visible 等。这样,channel edit 组件就初步具备了显示弹层的功能。
- 导入必要的库和模块:在组件的 script 部分,首先导入 ref。这个 ref 在后续的代码中用于实现响应式编程,例如对 dialogue visible 变量的操作。通过成功导入 ref,为组件的进一步开发和功能实现奠定了基础。
五、组件对外暴露方法以实现交互功能
- 设计 open 方法实现添加和编辑的区分与弹层控制
- 根据参数判断操作类型:为了使组件具有更强的通用性和交互性,设计了一个 open 方法。这个方法接收一个参数,通过判断这个参数的内容来区分是添加还是编辑操作。如果传入的是一个空对象,这意味着当前的操作是添加,此时表单无需进行渲染,只需要显示一个空的弹层。如果传入的是一个包含完整信息数据的对象,例如有 ID、分类名称等信息,那么就表示当前的操作是编辑,在这种情况下,表单在渲染时需要根据传入的数据进行回显。
- 实现弹层显示功能:除了根据参数判断操作类型外,open 方法还需要负责打开弹层。通过修改 dialogue visible 的值为 true 来实现弹层的显示。这样,open 方法就同时具备了接收参数判断操作类型和控制弹层显示这两个重要功能。
- 向外暴露 open 方法并在父组件中应用组件
- 向外暴露方法:使用 define expose 宏函数将 open 方法向外暴露。这样做的好处是,在组件外部就可以调用这个 open 方法,并且可以传入相应的参数。这种方式比向外暴露属性更加灵活,因为通过方法可以实现更多的功能,比如传参实现不同的操作逻辑。
- 在父组件中应用组件并调用方法:在 article channel(父组件)位置,首先需要导入 channel edit 组件。导入成功后,在 EL table 下面应用这个组件,并给它添加一个 ref,比如将 ref 命名为 dialogue。这样,在父组件中就可以通过这个 ref 来获取到 channel edit 组件的实例。在添加或编辑操作的相关代码中,通过这个 ref 调用 open 方法。在添加操作时,传入一个空对象;在编辑操作时,传入包含完整信息数据的对象。通过这种方式,根据传入参数的不同,在组件内部可以实现不同的表单渲染逻辑,从而完成添加或编辑功能。
六、课程内容总结
本节课重点完成了文章分类添加和编辑操作中弹层相关的功能实现。首先,通过研究 element plus 官方文档,实现了弹层的显示功能,并进行了简单测试。然后,将弹层相关的代码封装成了 channel edit 组件,提高了代码的复用性。最后,对外暴露了 open 方法,通过在父组件中应用组件并调用 open 方法传参,实现了根据不同参数区分添加和编辑操作的功能,为后续的表单渲染和数据处理奠定了基础。
180
一、element plus 语言配置
完成基本静态结构搭建后,对 element plus 进行语言优化。其官方有中英配置,在 configure provide 全局配置中可操作多语言。修改el-config-provider绑定的locale变量实现切换,默认 “en”(英文),设为 “zh-cn” 则为中文。在 VS code 里,在 APP.vue 中用el-config-provider 包裹 <router-view />,导入中文包(import zhCn from 'element-plus/dist/locale/zh-cn.mjs'),可将项目组件语言设为中文。
二、文章分类下拉菜单组件封装
- 创建组件:将文章分类下拉菜单的 select 封装成ChannelSelect.vue组件,在 components 下新建文件存储。
- 获取数据:在ChannelSelect.vue组件内导入获取文章分类接口(artGetListService),定义方法在页面加载时发请求获取数据,存入articleList数组。
- 数据绑定与渲染:el-select 绑数据不能直接用 v - model,它关联的数据项是父组件传来的 prop 值。先完成静态结构渲染,配置 label 和 value 等属性。在父组件 articleManage中用 v - model 绑定变量(如分类 ID 相关变量)实现默认选中与联动。
三、组件双向绑定与参数配置
v-model
在 Vue 3 中的理解:在 Vue 3 中,v-model
是:model_value
和@update:model_value
的简写。
- 双向绑定实现:在ChannelSelect组件封装时,定义 props 接收 modelValue(类型支持 number 和 string),定义 emit 事件@update:modelValue="emit('update:modelValue', $event)。在组件内,设置时拆解 V- model,将父组件传来的modelValue设给 el-select,,同时监听
update:model_value
事件,当EL select
修改时触发该事件并将参数往上传递(emit('update:model_value', $event)
),实现双向绑定和数据实时更新。 - 请求参数配置:定义请求参数对象 params,含 name(默认第一页)、size(每页条数)、cate_id(文章分类 ID,支持 number 和 string,初始为空串)、state(默认空,表示未选中)等,V - model 与 cate_id及 state 绑定,方便修改请求参数和收集表单数据。
181
一、表格渲染准备
- 接口封装:
- 先根据接口文档封装获取文章列表的接口,是
get
请求且参数为query
参数。在VS code
的article.js相关代码处进行封装,函数命名为artGetListService,其接收参数是对象params
。配置请求地址为/my/article/list,get
或delete
请求时参数要放在params
里配置(post
请求则在data
里配置参数)。 - 在
articleManage
页面调用该接口发请求,声明getArticleList方法,使用await
等待artGetListService执行并将params.value
整个对象传过去,从API
下的article
文件导入该接口函数。
- 先根据接口文档封装获取文章列表的接口,是
- 数据处理与存储:
- 接口响应结果包含
data
(文章列表数据,格式为数组包对象)和total
(文章总条数),提前声明了article list
(数组)和total
(初始值为0
,用ref
定义)来存储对应数据。将响应结果中的文章列表数据赋值给articleList.value
,总条数赋值给total.value
,一进页面就调用函数基于params
参数获取文章列表。
- 接口响应结果包含
二、表格渲染及微调
- 初始渲染情况:
- 之前基于假数据已完成部分渲染工作,将获取的
ArticleList
配置给el-table
且按后台接口配置字段,若无接口字段问题则可直接渲染。但发表时间字段返回的是标准长格式时间,不符合需求,需进行格式化处理。
- 之前基于假数据已完成部分渲染工作,将获取的
- 日期格式化:
element plus
内置DJS
,无需额外装包。在utils
下新建format.js
文件封装日期格式化函数formatTime,基于dayjs对传入的时间参数time
格式化为YYYY年mm月dd日
的格式。- 在
articlemanage
页面导入formatTime函数并在发表时间处调用,调用时若对数据做处理,需写template
并解构出对应数据(如row.pub_date)传入函数,在Vue3
中通过调用方法来进行格式化,废弃了过滤器。
182
一、准备分页数据及组件使用
- 引入分页组件:使用
element plus
里的pagination
分页组件,在VS code
中找到其完整事例(All combined)解读参数,将该组件放在文章列表(el-table
)下方用于分页功能实现。 - 参数绑定:
current page
绑定到params
里的page num
(当前页),page size
绑定到params
里当前生效的每页条数。page sizes
用于配置可供用户选择的每页条数,可设置如2
、3
、5
、10
等选项,注意要包含默认生效的每页条数。- 对于
small
(是否小一点)、disable
(是否禁用)、background
(是否加背景颜色)等属性,直接在后面赋予布尔值即可,设置background
可添加背景底色。
- 工具栏配置:
layout
属性用于控制分页组件下方工具栏各元素的显示、顺序等,各元素(如total
、sizes
、prev
、next
、jumper
等)用逗号隔开,可按需调整顺序,例如将jumper
挪到第一个,相应功能位置也会改变,total
需绑定上面已定义的total
变量。
二、配置分页相关事件及样式
- 事件配置:
- 需配置两个事件,size-change(对应onSizeChange函数)和current-change(对应onCurrentChange函数),分别在每页条数变化和当前页变化时触发,函数能接收
number
类型的参数value
,可在这两个函数内编写处理分页逻辑的代码。 - 如在onSizeChange函数中,当每页条数变化时,将
params.value.page
设为1
(从第一页开始渲染),同时更新相关的size
参数,并基于新的当前页和每页条数调用get
getArticleList()函数重新渲染数据;在onCurrentChange函数中,更新params.value.pagenum里对应的当前页配置,再基于最新当前页调用getArticleList()函数渲染数据。
- 需配置两个事件,size-change(对应onSizeChange函数)和current-change(对应onCurrentChange函数),分别在每页条数变化和当前页变化时触发,函数能接收
- 样式调整:给el-pagination添加
style
样式,可设置如margin top 20
以及flex
布局相关属性(如display flex
、justify-content: flex-end)来调整分页组件的位置和整体布局,使其居右且距顶部一定距离。
183
一、添加加载(loading)效果
- 准备变量与绑定:
- 定义一个布尔值变量(如
loading
,初始值设为false
)用于表示加载状态。 - 在
EL table
上添加指令v-loading
并绑定该变量,以此来控制表格的加载效果显示。
- 定义一个布尔值变量(如
- 控制加载状态:在发送请求获取文章列表数据前,将
loading
变量的值设为true
(开启加载),当请求完成拿到结果后,再将其设为false
(关闭加载),如此实现加载效果的展示,使分页功能在视觉上更完善。
二、实现搜索与重置功能
- 搜索功能实现:
- 在
VS code
中为搜索按钮注册点击事件(@click="
onSearch"
),并编写onSearch函数逻辑。 - 搜索逻辑主要是按照最新条件重新请求数据,由于条件改变,先将页码重置(
params.value.page name = 1
),再调用getArticleList()函数重新渲染,以展示符合新搜索条件的结果,例如按关键词 “体育” 等进行搜索能得到相应的数据展示及分页情况变化。
- 在
- 重置功能实现:
- 为重置按钮注册点击事件(
@click="
onReset"
),并定义onReset函数逻辑。 - 重置功能是清空之前关于分类和发布状态等筛选条件,具体操作是将params.value.cate_id = '' 和 params.value.state = ''都设为
empty
(空值),同时也要重置页码并重新渲染(同样先params.value.pagenum = 1,再调用getArticleList()函数),使得页面恢复到可检索全部内容的初始状态
- 为重置按钮注册点击事件(
184
一、认识并使用抽屉组件
- 抽屉与对话框对比及选择依据:
添加和编辑文章共用一个抽屉组件,抽屉与dialog
使用思路类似,但抽屉空间更大,可放置更多内容,能根据需求选择使用。Drawer
组件与dialog
几乎有相同的 API,会用dialog
基本就会用Drawer
。 - 抽屉组件基本使用方法:
- 在
element plus
官网查看Drawer
组件源代码可知,可通过v-model
绑定布尔值控制其显示隐藏,绑定title
控制标题,direction
控制弹出方向(默认从右边出来,不配此参数时按默认情况),before-close可设置关闭前询问等(一般可不加)。 - 在
VS code
的ArticleManager
组件里,将Drawer
放在分页下面进行渲染尝试。定义布尔值变量(如visibleDrawer)控制抽屉显示隐藏,在Drawer
组件上用v-model
绑定该变量,设置标题及简单内容(如hi there
),并为添加文章按钮注册点击事件(@click="
onAddArticle"
),在onAddArticle函数里通过改变visibleDrawer.value
的值来控制抽屉显示,可尝试配置direction
参数改变弹出方向(如设置为top to bottom
可实现从上往下弹出),还能通过size
参数传入百分比或像素值控制抽屉大小(如设置size = 50%
)。
- 在
二、封装抽屉组件
- 组件封装过程:
在components
文件夹下新建ArticleEdit组件文件,将之前写的Drawer
结构剪切放入其中,同时把控制显示隐藏的变量(如visibleDrawer)也剪切过来,不过此时组件未对外暴露内容。 - 向外暴露方法及功能设计:
- 向外暴露
open
方法,功能一是根据传入参数区分添加(传空对象)还是编辑(传带ID
的对象),二是能控制抽屉打开显示(通过改变visibleDrawer.value
的值实现)。使用defineExpose
来暴露open
方法,使得在外部能调用该方法打开抽屉组件进行相应操作。 - 在合适位置导入ArticleEdit组件并添加
ref
(如articleEditRef)进行绑定,之后无论是添加还是编辑操作,都通过该ref
找到组件并调用open
方法,传入相应参数(空对象表示添加,带ID
的对象表示编辑),通过控制台打印情况可验证参数传递及功能实现情况,为后续回显、编辑数据等操作做准备。
- 向外暴露
185
-
表单数据准备:
- 根据发布文章接口文档,需传递标题(
title
)、分类ID
(cat_id
)、封面图片(cover_image
)、内容(content
)、状态(state
)这五个参数,为此创建formModel
数据(const formModel = ref({...})
),并添加对应注释说明各参数类型。 - 点击编辑时,若
row.id
存在,需基于该ID
发请求获取编辑详情数据用于回显;若为添加操作,要重置formModel
数据,可先定义defaultfForm
作为默认表单数据,通过展开运算符进行重置(formModel.value = {...defaultfForm}
)。
- 根据发布文章接口文档,需传递标题(
-
抽屉表单结构准备:
- 从笔记中复制完善抽屉表单结构的代码到对应位置,替换原
template
内容,导入之前封装的ChannelSelect
组件(import ChannelSelect from './ChannelSelect'
- 从笔记中复制完善抽屉表单结构的代码到对应位置,替换原
186
文件上传功能实现(实质为文件预览及相关处理)
- 确定文件上传方式:
- 分析文件上传的两种常见做法,一种是选择图片时就立即上传,后台返回 URL 地址,下次发布时提交该 URL,但可能产生无效上传及垃圾图片,增加服务器负担;另一种是先进行本地预览,在点发布或草稿时才将图片及其他数据一起上传,服务器压力较小但提交时可能有卡顿。查看接口文档,发现无单独文件提交接口且发布接口通过
form- data
方式提交文件对象,确定采用后一种与发布一起提交的方式,即先做本地预览。
- 分析文件上传的两种常见做法,一种是选择图片时就立即上传,后台返回 URL 地址,下次发布时提交该 URL,但可能产生无效上传及垃圾图片,增加服务器负担;另一种是先进行本地预览,在点发布或草稿时才将图片及其他数据一起上传,服务器压力较小但提交时可能有卡顿。查看接口文档,发现无单独文件提交接口且发布接口通过
- 使用
el-upload
组件及相关配置调整:- 组件默认行为及钩子函数了解:
el-upload
组件默认支持自动文件上传,有相关配置如action
(配置后台提交图片地址,默认请求方式为POST
,参数name
默认是file
),还有上传前校验的before-upload
钩子(可限制图片格式、大小等)以及上传成功触发的success
钩子等。 - 根据需求修改配置:因采用最后一起提交的方式,只需前端本地预览图片,所以要关闭
el-upload
组件的自动上传功能(将auto-upload
属性设为false
),不需要配置action
、success
等与自动上传相关的参数,before-upload
钩子若想进行提交前校验等操作可保留配置,否则也可不配。
- 组件默认行为及钩子函数了解:
- 实现文件预览功能:
- 数据准备及图标显示:定义
imageURL
(const imageURL = ref('')
)用于存储图片相关信息,默认值为空,通过v-if
控制,为空时展示+
图标(需从element-plus
导入该图标组件),实现初始状态下的界面显示。 - 监听文件选择及预览实现:利用
el-upload
组件提供的on-change
钩子监听文件选择,绑定自定义方法(如onSelectFile
),该方法在文件选择时可获取选择的文件对象(单文件时取第一个参数对应的对象),然后通过URL.createObjectURL(uploadFile.raw)
将文件对象转换为可用于预览的地址,并赋值给imageURL
,实现图片在前端的预览功能,可多次选择更换图片进行预览。
- 数据准备及图标显示:定义
- 文件上传相关样式美化:
- 从笔记中获取提前配置好的文件上传样式代码
- 数据收集及后续注意事项:
- 在收集数据时,要将
upload
相关的图片文件对象存入formModel
里,以便后续发布时能以formdata
的方式提交该文件对象。
- 在收集数据时,要将
187
副本编辑器( vue-quill)相关操作及设置
-
安装包:
- npm install @vueup/vue-quill@latest --save
-
注册为局部组件:
- 查看其使用说明中提到在单文件组件里可进行全局注册(如
const APP = createApp(App); APP.component()
方式),但因仅在当前模块使用,选择局部注册即可。将相关包导入到使用的地方,完成局部注册后,就能在对应的副本编辑器位置使用了。
- 查看其使用说明中提到在单文件组件里可进行全局注册(如
-
设置双向绑定:
- 在副本编辑器处通过
v-model:content="formModel.content"
的形式进行数据绑定,使副本编辑器与formModel
里的content
实现双向绑定,方便数据同步更新。同时要注意设置content-type
的内容格式,明确其为HTML
字符串类型,确保数据能正确解析展示。
- 在副本编辑器处通过
188
- 发布功能核心业务实现:
- 接口封装:根据接口文档,封装添加文章接口(artPublishService),请求方式为
POST
,请求地址为特定路径(如/my/article/
add),参数包含title
、cat ID
、content
、cover image
、state
且需以formData格式提交。在封装的接口函数中,使用request.post
发起请求,传入正确的路径和参数对象。 - 页面事件注册与状态处理:在
articleEdit
页面,为发布和草稿按钮分别注册点击事件(onPublish
和对应的草稿事件处理函数)。根据按钮状态设置state
值(已发布或草稿)并存入formModel
对象中。由于接口需要 formData对象,需将普通对象formModel
转换,创建formData
实例,遍历formModel.value
,把其中的数据通过append
方法添加到formData
对象中。 - 编辑与添加操作区分:通过判断
formModel.value.id
是否存在区分编辑和添加操作。若存在则为编辑操作(先预留 ),不存在则为添加操作,添加操作调用封装好的发布接口并传入转换后的formData
对象。若请求成功,给出提示信息(如 “添加成功”)并关闭抽屉组件(visibleDrawer = false
),同时触发emit('success', type)
事件通知父组件操作结果,其中type
区分添加或编辑,以便父组件进行不同的处理。
- 接口封装:根据接口文档,封装添加文章接口(artPublishService),请求方式为
- 父组件响应与页面渲染处理:
- 在父组件
articleManage
中,监听子组件触发的success
事件(@success="onSuccess"
)。在事件处理函数onSuccess
中,根据传入的type
判断是添加还是编辑操作。若为添加操作,基于总条数total
和每页条数params.value.size
计算最后一页页码(需先手动加 1 再计算并向上取整),更新当前页码为计算出的最后一页页码后再调用获取文章列表的方法(getArticleList
)进行页面渲染;若为编辑操作,则直接调用getArticleList
渲染当前页。
- 在父组件
- 添加操作完成后的重置处理:
- 在
open
函数中,除了重置表单数据,还需手动重置图片预览地址(imageURL.value = ''
)和富文本编辑器内容。为富文本编辑器声明ref
(const editorRef = ref(null)
)并与组件绑定,通过editorRef.value.setHTML('')
调用其官方提供的setHTML
方法将内容清空,确保每次打开添加文章抽屉时,所有内容都能重置干净,完成整个添加功能的实现。nexTick(()=>{editorRef.value.setHTML('')
})
- 在
189
编辑功能实现相关内容
-
编辑回显功能实现
- 接口封装:
- 因编辑功能需回显数据(如封面、内容等),所以要封装获取文章详情的接口。在
article.go.js
文件中,封装artGetDetailService
接口,通过request.get
发起请求,请求地址为/my/article/info
,参数为{params: {id}}
,这里以ID
作为唯一标识获取文章详情,其中cover image
的值需后续自行拼接服务器前缀地址(相关baseURL
已按序导出,可按需导入配置)。
- 因编辑功能需回显数据(如封面、内容等),所以要封装获取文章详情的接口。在
- 回显数据获取与处理:
- 在
articleEditor
组件的open
方法中调用封装好的artGetDetailService
接口,传入当前行数据中的ID
(const res = await artGetDetailService(row.id))获取文章详情数据,先将获取到的数据整体存入formModel.value
(formModel.value = res.data.data)实现大部分数据的回显。 - 对于封面图片的回显,由于后台返回的cover_img地址无前缀,需从
request.js
中导入baseURL
,在open
方法中进行拼接处理(imageURL.value = baseURL + formModel.value.cover_image
),完成封面图片的正确回显。 - 但后续发现问题,更新文章详情接口要求cover_img为
file
对象格式,而目前存到form
对象中的是字符串格式的网络地址,所以需要进行转换。 - 借助
GPT
提供的方法,在浏览器环境中,要先通过axios
下载图片,再转成Blob对象,最后创建file
对象并将其收入其中。导入axios
(import axios from 'axios'
)后,调用相应方法(formModel.value.cover_img = await imageUrlToFile(
imgUrl.value, formModel.value.cover_img),将网络图片地址和提取的文件名传入,得到file
对象后更新formModel.value.cover_image = file
,以便后续提交时符合后台要求。
- 在
- 接口封装:
-
编辑提交功能实现
- 接口封装:
- 编辑提交需封装编辑文章接口,在
VS code
中找到对应文件,封装artEditService
接口,请求方式为put
,请求地址为/my/article/info
,直接传入data
参数(对于put,post
请求直接写参数,不像get
、delete
请求需在对象里写params
再写参数)。
- 编辑提交需封装编辑文章接口,在
- 接口调用与后续处理:
- 在
articleEditor
组件提交的位置调用封装好的artEditService
接口,传入formData
对象(注意别传错对象类型),若请求成功给出提示信息(ElMessage.success('编辑成功')),同时关闭相关组件(visibleDrawer.value = false
)。 - 通知父组件
articleManager
编辑操作成功,父组件监听到success
事件且接收到editor
标识时,只需重新渲染当前页即可,实现编辑文章的提交功能。
- 在
- 接口封装:
193
个人中心基本资料功能实现相关内容
-
项目准备及组件搭建:
- 之前完成了对 AI 相关认知及 GPT、Copilot 使用学习,现进行个人中心项目实战,先着手实现基本资料功能。在
VS code
中找到user
下的userProfile
部分搭建框架,引入之前定义的pageContainer
组件(需先导入相关配置skipped setup
),按其封装规则通过title
配置标题为 “基本资料”,主体部分用默认插槽、右侧用具名插槽配置内容,此处主体内容为表单。
- 之前完成了对 AI 相关认知及 GPT、Copilot 使用学习,现进行个人中心项目实战,先着手实现基本资料功能。在
-
利用 GPT 生成表单代码及调整:
- 为快速生成表单代码,打开 GPT 并输入详细提示词,基于
element plus
和View 3
语法,要求生成包含四行的表单组件代码(前三行是输入框,分别对应登录名称、昵称、邮箱,前两个输入框可输入,第一个输入框禁用;第四行是提交修改按钮,同时对昵称和邮箱设置相应校验规则)。 - 将 GPT 生成的代码复制到
VS code
对应位置,按需导入相关依赖(如raf
),运行项目(PNPM dev
)后发现因View 3
语法问题,模板部分写法需调整(要加#default
表示默认插槽),修正后可正常渲染展示表单,再根据实际情况对表单内容进行修改,如将 “登录名称” 改为 “用户名”,对校验规则也可按需进一步细化调整(如通过正则更精准控制昵称格式等)。
- 为快速生成表单代码,打开 GPT 并输入详细提示词,基于
-
数据回显相关操作:
- 通过查看
View
调试工具可知store
中有user
相关信息用于页面渲染,先从store
中获取user
数据,导入useUserStore
(import { useUserStore } from '@/stores'
),利用其解构出所需字段(如email
、nickname
、ID
、userName
等),用解构出的数据初始化表单数据(定义formRef
,const formRef = ref({...解构出的字段...})
,注意避免重名问题,修改绑定ref
名称),实现基本的数据回显功能,表单能正常展示且校验、修改等操作也可正常进行。
- 通过查看
-
接口封装与提交修改操作:
- 查看接口文档中 “更新个人信息” 接口,其请求方式为
put
,地址为/my/user/info
,参数重点有ID
、nickname
、email
(头像可选),在VS code
的API
下的user
文件中封装接口,定义updateInfoService
(export const updateInfoService = () => request.put('/my/user/info', data)
,可对data
参数结构化清晰展示参数情况)。 - 在表单提交处,先校验表单(
await formRef.value.validate()
),校验通过后调用封装好的接口(await updateInfoService(formRef.value)
,需从user
模块导入该方法)进行提交修改。 - 由于前端发请求修改后台数据后,前端页面数据未实时更新,需利用
user
模块中的getUser
方法获取最新个人信息来更新前端数据,解构出getUser
方法后调用它实现数据实时更新,完成整个基本资料修改提交及数据更新的功能实现。
- 查看接口文档中 “更新个人信息” 接口,其请求方式为
194
个人中心更换头像功能实现相关内容
组件框架搭建:最外层使用 pageContainer 组件包裹,在对应位置配置 title 为 “更换头像”
-
上传组件配置:
- 从
elementPlus
中找到el-upload
组件用于上传功能,可参考之前用户头像相关使用方式,将其内容复制过来使用。对于el-upload
组件内的一些属性配置,如action
、onSuccess
等此次不需要配置。 - 准备图片相关数据,定义
testImageURL
(const testImageURL = ref('')
,类型为ref
,利用Vue
相关特性生成)用于提供图片预览的地址,若该地址为空则显示默认的加号图标。 - 查看接口文档可知更新用户头像接口请求参数是
base64
字符串类型,所以要考虑将图片转为base64
格式,同时配置el-upload
组件的autoUpload
属性为false
,关闭自动上传功能,因为要按照接口要求的格式进行后续处理。 - 在导入
elementPlus
图标(import { Icon } from 'elementPlus/icons-vue'
)时遇到找不到包的问题,修正导入路径后解决,并且可以为上传组件添加一些样式
- 从
按钮组件配置
- 添加两个
el-button
按钮:- 在
el-upload
组件下方添加两个按钮,分别配置:- “选择图片” 按钮:
type
属性为primary
。 - “上传头像” 按钮:
type
属性为success
。
- “选择图片” 按钮:
- 通过
:icon
属性为按钮添加图标(如:icon="Plus")
- 在
195
个人中心更换头像功能实现步骤总结
-
选择预览图片功能实现:
- 点击事件关联与触发:为实现无论是点击上传组件还是下方按钮都能选择图片的功能,先给上传组件添加
ref
(const uploadRef = ref(null)
)并在模板中绑定(ref="uploadRef"
)。在按钮的点击事件处理函数中,通过uploadRef.value
获取到组件实例,再使用querySelector
找到其内部的输入框元素并触发点击事件(uploadRef.value.querySelector('input').click()
),从而实现点击按钮也能弹出文件选择框的效果。 - 图片预览实现:当选择图片时会触发
el-upload
组件的on-change
事件,在事件处理函数(onSelectFile
)中,可利用相关方法(如URL.createObjectURL
)处理图片以实现预览功能。同时,为了得到base64
格式的图片用于后续提交,引入FileReader
对象(const reader = new FileReader()
),通过reader.readAsDataURL
读取图片并在onload
事件中将结果存储到用于显示图片的imageURL.value
中,这样既实现了图片预览又得到了符合接口要求格式的图片数据。
- 点击事件关联与触发:为实现无论是点击上传组件还是下方按钮都能选择图片的功能,先给上传组件添加
-
上传头像功能实现:
- 接口封装:查看接口文档中 “更新用户头像” 接口,其请求参数为
avatar
(base64
格式),在API
下的user
文件中封装接口。先纠正自动生成代码中的错误,将请求方式post
改为patch
,请求地址修正为正确的路径(如/my/updateAvatar
),参数只需传入avatar
({ avatar: base64格式图片数据 }
),定义updateAvatarService
函数用于该接口调用(export const updateAvatarService = () => request.patch('/my/updateAvatar', { avatar: base64格式图片数据 })
)。 - 接口调用与数据更新:在 “上传头像” 按钮的点击事件处理函数(
onUploadAvatar
)中,调用封装好的updateAvatarService
接口,传入imageURL.value
(即base64
格式的图片数据)进行头像更新操作。接口调用成功后,为使前端页面显示最新头像数据,需调用userStore
中的getUser
方法重新获取用户信息以更新页面,同时给出 “更新成功” 的提示信息给用户,完成整个更换头像功能的上传与数据更新流程。
- 接口封装:查看接口文档中 “更新用户头像” 接口,其请求参数为