Vue3.0项目实战(四)——大事件管理系统文章管理页面 - [element-plus 强化]

目录

1. 文章列表渲染

1.1 基本架子搭建

1.2 中英国际化处理

1.3 文章分类选择

1.4 封装 API 接口,请求渲染文章列表

2. 分页渲染 [element-plus 分页]

3. 添加 loading 处理

4. 搜索 和 重置功能

5. 文章发布&修改 [element-plus - 抽屉]

5.1 点击显示抽屉

5.2 封装抽屉组件 ArticleEdit

5.3 完善抽屉表单结构

5.4 上传图片文件预览 [element-plus - 文件预览]

5.5 富文本编辑器 [ vue-quill ]

5.6 添加文章功能

5.7 添加完成后的内容重置

5.8 编辑文章回显

5.9 编辑文章功能

6. 文章删除


1. 文章列表渲染

1.1 基本架子搭建

① 搜索表单

 <!-- 表单区域   inline 将 el-form-item 在一行显示 -->
      <el-form inline>
        <el-form-item label="文章分类:">
          <!-- <el-select placeholder="请选择" size="large" style="width: 240px">
            <el-option label="体育" value="1111" />
            <el-option label="新闻" value="2222" />
          </el-select> -->
          <!-- vue2.0 v-model 是 :value 和 @input 的简写,
            相当于传递了一个 value 属性给子组件,自定义的事件是 input 事件 -->
          <!-- vue3.0 v-model 是 :modelValue 和 @update:modelValue 的简写 -->
          <!-- 或者也可以写为: 
          <ChannelSelect :modelValue="params.cate_id"></ChannelSelect> 
          -->
          <ChannelSelect v-model="params.cate_id"></ChannelSelect>
        </el-form-item>
        <el-form-item label="发布状态:">
          <el-select
            placeholder="请选择"
            size="large"
            style="width: 240px"
            v-model="params.state"
          >
            <el-option label="已发布" value="已发布" />
            <el-option label="草稿" value="草稿" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSearch">搜索</el-button>
          <el-button @click="onReset">重置</el-button>
        </el-form-item>
      </el-form>
      <!-- 表单区域 -->

② 文章列表表格准备,模拟假数据渲染

  • el-link 文字超链接

    • underline是否下划线
<!-- 文章列表 -->
      <el-table
        style="width: 100%"
        stripe
        :data="tableData"
        v-loading="loading"
      >
        <el-table-column label="文章标题" prop="title" align="center">
          <template #default="scope">
            <el-link type="primary" :underline="false">
              {{ scope.row.title }}
            </el-link>
          </template>
        </el-table-column>
        <el-table-column
          label="分类"
          prop="cate_name"
          align="center"
        ></el-table-column>
        <el-table-column label="发布时间" prop="pub_date" align="center">
          <template #default="scope">
            {{ formatTime(scope.row.pub_date) }}
          </template>
        </el-table-column>
        <el-table-column
          label="状态"
          prop="state"
          align="center"
        ></el-table-column>
        <el-table-column label="操作" align="center">
          <template #default="scope">
            <div
              style="
                display: flex;
                justify-content: center;
                align-items: center;
              "
            >
              <el-button
                type="primary"
                :icon="Edit"
                circle
                plain
                @click="onEditArticle(scope.row)"
              ></el-button>
              <el-button
                type="danger"
                plain
                @click="onDeleteArticle(scope.row)"
                :icon="Delete"
                circle
              ></el-button>
            </div>
          </template>
        </el-table-column>
        <template #empty>
          <el-empty description="没有数据"></el-empty>
        </template>
      </el-table>

1.2 中英国际化处理

默认是英文的,由于这里不涉及切换, 所以在 App.vue 中直接导入设置成中文即可,

① 全局配置

② ConfigProvider

1.3 文章分类选择

为了便于维护,直接拆分成一个小组件 ChannelSelect.vue

① 新建 article/manage/components/ChannelSelect.vue

② 页面中导入渲染

③ 调用接口,动态渲染下拉分类,设计成 v-model 的使用方式

  • vue2.0 v-model 是 :value 和 @input 的简写,相当于传递了一个 value 属性给子组件,自定义的事件是 input 事件。

  • vue3.0 v-model 是 :modelValue 和 @update:modelValue 的简写。相当于传递了一个 modelValue 属性给子组件,自定义的事件是 update:modelValue 事件。

④ 父组件定义参数绑定

⑤ 发布状态,也绑定一下,便于将来提交表单

1.4 封装 API 接口,请求渲染文章列表

① api/article.js 封装接口

② 页面中调用保存数据

③ 新建 utils/format.js 封装格式化日期函数

④ 导入使用(vue 3.0 废弃了过滤器)

2. 分页渲染 [element-plus 分页]

① 分页组件

  • current-page / v-model:current-page:当前页数
  • page-size / v-model:page-size:每页显示条目个数
  • page-sizes:每页显示个数选择器的选项设置

  • background:是否为分页按钮添加背景色

  • layout:组件布局,子组件名用逗号分隔

  • total:总条目数

  • size-change:page-size 改变时触发

  • current-change:current-page 改变时触发

② 提供分页修改逻辑

  • 每页显示数据条数,处理函数
  • 当前页改变的时候触发,

3. 添加 loading 处理

① 准备数据

② el-table上面绑定

③ 发送请求时添加 loading

4. 搜索 和 重置功能

① 注册事件

② 绑定处理

5. 文章发布&修改 [element-plus - 抽屉]

5.1 点击显示抽屉

① 准备数据

② 准备抽屉容器

③ 点击修改布尔值显示抽屉

<el-button type="primary" @click="onAddArticle">发布文章</el-button>

const drawer = ref(false)
const onAddArticle = () => {
  drawer.value = true
}

5.2 封装抽屉组件 ArticleEdit

添加 和 编辑,可以共用一个抽屉,所以可以将抽屉封装成一个组件

组件对外暴露一个方法 open, 基于 open 的参数,初始化表单数据,并判断区分是添加 还是 编辑

  • open({ }) => 添加操作,添加表单初始化无数据
  • open({ id: xx, ... }) => 编辑操作,编辑表单初始化需回显

具体实现:

① 封装组件 article/manage/components/ArticleEdit.vue,向外暴露 open 方法

② 父组件中通过 ref 绑定抽屉组件

③ 点击调用方法显示弹窗

5.3 完善抽屉表单结构

① 准备数据

② 准备 form 表单结构

 <el-form :model="formModel">
      <el-form-item label="文章标题:" prop="title">
        <el-input
          placeholder="请输入文章标题"
          v-model="formModel.title"
        ></el-input>
      </el-form-item>
      <el-form-item label="文章分类:" prop="cate_id">
        <ChannelSelect
          v-model="formModel.cate_id"
          :width="'100%'"
        ></ChannelSelect>
      </el-form-item>
      <el-form-item label="文章封面:" prop="cover_img">
        <!--
          此处需要关闭 element-plus 的自动上传,不需要配置 action 等参数
          只需要做前端的本地预览图片即可,无需在提交之前上传图片
          语法: Window.ULR.createObjectURL() 创建本地预览的地址,来预览图片
          show-file-list	是否显示已上传文件列表
          on-change	文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
          auto-upload	是否自动上传文件
         -->
        <el-upload
          class="avatar-uploader"
          :show-file-list="false"
          :on-change="onUploadFile"
          :auto-upload="false"
        >
          <img v-if="imageUrl" :src="imageUrl" class="avatar" />
          <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
        </el-upload>
      </el-form-item>
      <el-form-item label="文章内容:" prop="content">
        <div class="editor">
          <!-- 富文本编辑器 -->
          <QuillEditor
            ref="editorRef"
            theme="snow"
            v-model:content="formModel.content"
            content-type="html"
          />
        </div>
      </el-form-item>
      <el-form-item prop="state">
        <el-button type="primary" @click="onPublicArticle('已发布')">
          发布
        </el-button>
        <el-button type="info" @click="onPublicArticle('草稿')">草稿</el-button>
      </el-form-item>
    </el-form>

③ 一打开默认重置添加的 form 表单数据

④ 扩展 下拉菜单 width props

5.4 上传图片文件预览 [element-plus - 文件预览]

① 关闭自动上传,准备结构

  • 此处需要关闭 element-plus 的自动上传,不需要配置 action 等参数

  • 只需要做前端的本地预览图片即可,无需在提交之前上传图片

  • 语法: Window.ULR.createObjectURL() 创建本地预览的地址,来预览图片

  • show-file-list  是否显示已上传文件列表

  • on-change 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用

  • auto-upload 是否自动上传文件

② 准备数据 和 选择图片的处理逻辑

  • 为选中的文件创建一个临时的、本地的 URL,以便在页面上可以直接预览或访问这个文件,而不需要立即上传到服务器
  • window.URL.createObjectURL(file):使用浏览器的 URL.createObjectURL() 方法,为传入的 file 对象(即用户选择的文件)生成一个本地的临时 URL。

    • 这个 URL 是一个字符串,指向本地的文件资源。blob:http://localhost:5173/d2d71faf-2c60-4fd9-92cb-ea0eeae052cf

    • blob: URL 可以直接用作 HTML 标签(如 <img>、<video>、<audio> 等)的 src 属性,无需进一步处理。

  • 立即将图片对象,存入 formModel.value.cover_img 中,将来点击发布按钮的时候,提交给后台的服务器

③ 样式美化

5.5 富文本编辑器 [ vue-quill ]

官网地址:VueQuill | Rich Text Editor Component for Vue 3

① 安装包

  • pnpm add @vueup/vue-quill@latest

② 注册成局部组件

③ 页面中使用绑定

④ 样式美化

5.6 添加文章功能

① 封装添加接口

② 注册点击事件调用

  • 提交给后台的 data 是一个 FormDate 对象

③ 父组件监听事件,重新渲染

5.7 添加完成后的内容重置

5.8 编辑文章回显

如果是编辑操作,一打开抽屉,就需要发送请求,获取数据进行回显

① 封装接口,根据 id 获取详情数据

② 页面中调用渲染

  • 显示图片 "cover_img": "/uploads/885eb38f6270eb10b42aedadd84fea23.jpg",需要与基地址拼接

  • 提交给后台的图片数据格式是 file 对象格式

  • 所以需要将网络地址 "cover_img": "/uploads/885eb38f6270eb10b42aedadd84fea23.jpg",又转化成 file 对象,存储起来 (正常情况下, 后台应该两个都支持)

③ chatGPT prompt:封装一个函数,基于 axios, 网络图片地址,转 file 对象, 请注意:写中文注释

// 将网络图片地址转换为File对象
async function imageUrlToFile(url, fileName) {
  try {
    // 第一步:使用axios获取网络图片数据
    const response = await axios.get(url, { responseType: 'arraybuffer' });
    const imageData = response.data;

    // 第二步:将图片数据转换为Blob对象
    const blob = new Blob([imageData], { type: response.headers['content-type'] });

    // 第三步:创建一个新的File对象
    const file = new File([blob], fileName, { type: blob.type });

    return file;
  } catch (error) {
    console.error('将图片转换为File对象时发生错误:', error);
    throw error;
  }
}

5.9 编辑文章功能

① 封装编辑接口

② 提交时调用

6. 文章删除

① 封装删除接口

② 页面中添加确认框调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值