Vue3电影中后台开发纪实(三):数据展示
@拿到热映数据
使用POSTMAN提前向后台插入电影数据
配置全局代理
vite.config.js
// 配置前端服务地址和端口 server: { host: "0.0.0.0", port: 5173, // 是否开启 https https: false, // 让开发服务器帮我们做代理 proxy: { // http://localhost:5173/api "/api": { target: "http://localhost:8173", //API服务地址 changeOrigin: true, //开启跨域 rewrite: (path) => path.replace(/^\/api/, ""), }, }, }, 复制代码
配置网络应用层
src/api/movieApi.js
import axios from "axios"; import { doGet } from "./service/crud"; /* 获取正在热映列表 */ export async function getPlayings() { // localhost:5173/api/film/0 => vite会将该地址代理到localhost:8173/film/0 const {arr:films} = await doGet(`/film/0`); return films; } 复制代码
组件挂载时获取数据
src/views/film/Playing.vue
import { getPlayings } from "@api/movieApi"; /* 组件挂载完毕后发起AJAX请求 */ onMounted(async () => { const films = await getPlayings(); console.log("films=", films); }); 复制代码
@表格展示数据
分页加载
src/views/film/Playing.vue
/* 完整电影列表 */ const tableData = ref([]); /* 要显示的分页数据 */ const currentPage = ref(1); const computedData = computed(() => tableData.value.slice((currentPage.value - 1) * 10, currentPage.value * 10) ); /* 组件挂载完毕后发起AJAX请求 */ onMounted(async () => { const films = await getPlayings(); console.log("films=", films); tableData.value = films; }); 复制代码
表格列展示数据
<el-table :data="computedData" stripe style="width: 100%" :default-sort="{ prop: 'date', order: 'ascending' }" @selection-change="handleSelectionChange" > <!-- 多选显示栏 --> <el-table-column type="selection" width="40" /> <!-- fixed固定 sortable字段可排序 label=当前列标题 width当前列像素宽度 --> <el-table-column sortable fixed prop="filmId" label="id" width="100" /> <!-- 片名 --> <el-table-column sortable prop="name" label="片名" width="180" /> <!-- 海报 --> <el-table-column prop="poster" label="海报" width="60" > <template #default="{row:{poster}}"> <div style="display: flex; align-items: center"> <el-image :src="poster" /> </div> </template> </el-table-column> <!-- 主演 --> <el-table-column sortable prop="actors" label="主演" :formatter="formatActors" width="200" /> <!-- 国家 --> <el-table-column sortable prop="nation" label="国家" width="150" /> <!-- 类型 --> <el-table-column sortable prop="category" label="类型" width="150" /> <!-- 片长 --> <el-table-column sortable prop="runtime" label="片长" width="100" /> <!-- 评分 --> <el-table-column sortable prop="grade" label="评分" width="100" /> <!-- 首映日期 --> <el-table-column sortable prop="premiereAt" label="首映日期" :formatter="formatPremierAt" width="150" /> <!-- fixed="right"右侧固定 --> <el-table-column fixed="right" label="操作" width="90"> <!-- 覆盖为小号圆形的编辑按钮与删除按钮 --> <template #default> <el-button type="primary" :icon="Edit" circle size="small" /> <el-button type="danger" :icon="Delete" circle size="small" /> </template> </el-table-column> </el-table> 复制代码
数据格式化
/* 数据格式化函数 */ const formatPremierAt = (row, column, cellValue, index) => { // console.log("row", row);//当前行数据 // console.log("column", column);//当前列信息 // console.log("cellValue", cellValue);//当前要格式化的单元格数据 // console.log("index", index);//当前行行号 return new Date(cellValue * 1000).toLocaleDateString().replaceAll("/", "-"); }; const formatActors = (row, column, cellValue, index) => { return ( cellValue .map((actor) => actor.name) .slice(0, 3) .join(",") + "等" ); }; 复制代码
展示电影海报
<!-- 海报 --> <el-table-column prop="poster" label="海报" width="60" > <!-- <template #default="scope"> --> <template #default="{row:{poster}}"> <div style="display: flex; align-items: center"> <!-- 这里我们通过一个简单的测试发现scope.row.poster即要显示的海报数据 --> <!-- <el-image :src="showScope(scope)" /> --> <el-image :src="poster" /> </div> </template> </el-table-column> 复制代码
@跳转详情页
定义详情页路由
src/router/index.js
{ // 规定电影id为24个数字或小写字母 path: "/film/:id(\\d+)", name: "detail", meta: { hideTabbar: true }, component: () => import("../views/DetailView.vue"), }, 复制代码
跳转详情页
src/views/Playing.vue
<!-- 右侧固定的操作按钮区 --> <el-table-column fixed="right" label="操作" width="90"> <!-- action按钮区作用域插槽提供的数据中含有当前行信息row --> <!-- <template #default="scope"> --> <!-- 可以通过简单的测试查看一下作用域插槽中携带的数据 --> <!-- <el-button @click="showScope(scrope)"/> --> <!-- 从作用域插槽数据中解构出当前行id --> <template #default="{ row: { _id } }"> <!-- 点击Edit按钮 携带id跳转详情页 --> <el-button @click="$router.push(`/film/${_id}`)" type="primary" :icon="Edit" circle size="small" /> <el-button type="danger" :icon="Delete" circle size="small" /> </template> </el-table-column> 复制代码
@详情页数据展示
获取详情数据
src/views/Detail.vue
import { onMounted } from "vue"; import { useRoute } from "vue-router"; import { getDetail } from "@api/movieApi"; /* 获取影片详情 */ onMounted(async () => { const detail = await getDetail(route.params.id); console.log("detail=", detail); }); 复制代码
添加Loading效果
<template> <el-card v-loading="loading"> 正文内容... </el-card> </template> 复制代码
/* 获取影片详情 */ onMounted(async () => { loading.value = true; const detail = await getDetail(route.params.id); console.log("detail=", detail); /* 将detail中的数据同步到form中 表单中自动同步数据 */ // ... setTimeout(() => { loading.value = false; }, 500); }); 复制代码
定义表格数据
const form = reactive({}); /* 获取影片详情 */ onMounted(async () => { loading.value = true; const detail = await getDetail(route.params.id); console.log("detail=", detail); /* 将detail中的数据同步到form中 表单中自动同步数据 */ Object.assign(form, detail, { premiereAt: detail.premiereAt * 1000, // 影片类型 表单复选 应双向绑定一个数组 category: detail.category.split("|"), // 重构actcors数据 actors: detail.actors.map(({ name, role, avatarAddress }) => ({ name: `${name}-${role}`, url: avatarAddress, })), }); setTimeout(() => { loading.value = false; }, 500); }); 复制代码
表格展示数据
<template> <el-card v-loading="loading"> <template #header> <div class="card-header"> <span>影片详情</span> <!-- <el-button text>Operation button</el-button> --> </div> </template> <!-- 详情表单 --> <!-- form没有数据时不渲染form --> <el-form v-if="form[`name`]" :model="form" label-width="120px"> <!-- 片名关联form.name --> <el-form-item label="片名"> <el-input v-model="form.name" /> </el-form-item> <!-- 片长关联form.runtime --> <el-form-item label="片长"> <el-col :span="7"> <el-input v-model="form.runtime" type="number" /> </el-col> </el-form-item> <!-- 评分关联form.grade --> <el-form-item label="评分"> <el-col :span="7"> <el-input v-model="form.grade" /> </el-col> </el-form-item> <!-- 影片类型关联form.filmType.name --> <!-- filmType?.name 如果filmType不为null/undeined 就继续读取filmType?.name 否则直接返回null/undeined --> <el-form-item label="影片类型"> <el-select v-model="form.filmType.name" placeholder="please select your zone" > <el-option label="2D" value="2D" /> <el-option label="3D" value="3D" /> <el-option label="4D" value="4D" /> </el-select> </el-form-item> <!-- 影片类型关联form.premiereAt --> <el-form-item label="首映日期"> <el-col :span="8"> <el-date-picker v-model="form.premiereAt" type="date" placeholder="Pick a date" style="width: 100%" /> </el-col> </el-form-item> <!-- 在映关联form.isPresale --> <el-form-item label="在映"> <el-switch v-model="form.isPresale" /> </el-form-item> <!-- 影片类型关联form.category --> <el-form-item label="影片类型"> <el-checkbox-group v-model="form.category"> <el-checkbox label="爱情" name="category" /> <el-checkbox label="动作" name="category" /> <el-checkbox label="科幻" name="category" /> <el-checkbox label="历史" name="category" /> <el-checkbox label="悬疑" name="category" /> <el-checkbox label="喜剧" name="category" /> <el-checkbox label="战争" name="category" /> <el-checkbox label="剧情" name="category" /> <el-checkbox label="犯罪" name="category" /> <el-checkbox label="纪录片" name="category" /> </el-checkbox-group> </el-form-item> <!-- 国家关联form.nation --> <el-form-item label="国家"> <el-radio-group v-model="form.nation"> <el-radio label="中国大陆" /> <el-radio label="欧美" /> <el-radio label="日韩" /> <el-radio label="其它" /> </el-radio-group> </el-form-item> <!-- 演职人员关联form.actors --> <!-- :on-preview="handlePreview" :on-remove="handleRemove" --> <el-form-item label="演职人员"> <el-upload v-model:file-list="form.actors" class="upload-demo" list-type="picture-card" action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15" > <el-icon><Plus /></el-icon> </el-upload> </el-form-item> <!-- 海报关联form.poster --> <el-form-item label="海报"> <el-upload v-model:file-list="form.poster" action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15" list-type="picture-card" > <el-icon><Plus /></el-icon> </el-upload> </el-form-item> <!-- 剧情摘要form.synopsis --> <el-form-item label="剧情摘要"> <el-input v-model="form.synopsis" autosize type="textarea" /> </el-form-item> <!-- 提交与重置 --> <el-form-item> <el-button class="opBtn" type="primary" @click="onSubmit">更新</el-button> <el-button class="opBtn">重置</el-button> </el-form-item> </el-form> </el-card> </template>
作者:搬砖的乔布梭
链接:https://juejin.cn/post/7169131209983787039