效果概述
列表页面显示数据,点击跳转到对应的详情页,实现分页效果,点击回到顶部
具体效果
1.移动端适配 2.样式符合ui效果 3.处理时间格式 4.分页效果(上一页,下一页) 5.点击回到顶部效果(详情页和列表页都需实现) 6.解决接口跨域请求访问问题 7.路由跳转无bug 8.列表页面显示数据,点击跳转到对应的详情页
实现后效果图:
AlloyTeam(腾讯全端博客)
大致代码思路:
- 根页面:
使用 div 标签实现更多 router-view 标签接收数据 使用 router-link 实现回到顶部
列表页:
在 main.js 页面引入 axios 插件
在 main.js 页面引入 rem 移动端适配代码
在 main.js 页面引入 dayjs 处理时间格式插件
通过 rem 进行移动端适配
通过 axios 接口地址请求数据
通过 dayjs 处理时间格式
把请求到的数据赋值给data里的选项
在 html 代码中通过 v-for 实现循环,把数据渲染至视图中
通过正则获取到对象里的所有数字
用编程式导航实现跳转功能,并把列表的 id 通过 query 传递至跳转后的页面
通过 router-link 实现分页效果的跳转
通过路由滚动行为实现回到顶部效果
详情页:
使用 this.$route.query.id 获取上个页面通过 query 传递的 id 值
使用 axios 接口地址和接收到的 id 值请求详细数据
把请求到的数据赋值给data里的选项
把数据渲染到视图中
main.js代码:
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' Vue.config.productionTip = false // 引入rem适配 import '@/rem' // 引入 axios import axios from 'axios' //可以全局使用$axios Vue.prototype.$axios = axios // 引入dayjs import dayjs from "dayjs" //可以全局使用dayjs Vue.prototype.dayjs = dayjs; new Vue({ router, store, render: h => h(App) }).$mount('#app')
rem 适配页面代码:
const WIDTH = 375//如果是尺寸的设计稿在这里修改 const setView = () => { //设置html标签的fontSize document.documentElement.style.fontSize = (100 * document.documentElement.clientWidth / WIDTH) + 'px' } window.onresize = setView setView()
决跨域问题,在vue.config.js里添加代码
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, // 下面是解决跨域问题需要添加的内容 devServer:{ proxy:{ '/api':{ target:'http://118.190.39.123:8877/ ', // http://118.190.39.123:8877/ === /api pathRewrite:{ '^/api':'' // 重写 } } } } })
实现路由跳转页代码:
import Vue from 'vue' import VueRouter from 'vue-router' import HomeOne from '../views/HomeOne.vue' Vue.use(VueRouter) const routes = [ { path: '/', name: 'HomeOne', component: HomeOne }, { path: '/Details', name: 'Details', component: ()=>import('@/views/Details.vue') }, ] const router = new VueRouter({ // 只有调用了history.pushState()的时候才会触发这个方法 mode: 'history', base: process.env.BASE_URL, routes, // 使用这个方法实现期望滚动到哪一位置, scrollBehavior (to, from, savedPosition) { console.log(to,from,savedPosition); // 滚动到锚点 if (to.hash) { return { selector: to.hash, // 平滑滚动 behavior: 'smooth', } } } }) export default router
根页面代码:
<template> <div id="app"> <!-- 头部 --> <div class="HomeTop"> <!-- 更多 --> <div class="dian"> <span></span> </div> </div> <!-- 返回顶部 --> <router-link tag="div" to="#app" class="back">▲</router-link> <router-view></router-view> <!-- 底部 --> <div class="bottom">Copyright © 2022 AlloyTeam</div> </div> </template> <script> export default {}; </script> <style lang="scss"> * { margin: 0; padding: 0; box-sizing: border-box; font-size: 16px; } </style> <style lang="scss" scoped> #app { .HomeTop { width: 100%; height: 0.42rem; padding: 0 0.15rem; // background-color: red; border-bottom: 1px solid #ece7e7; display: flex; align-items: center; .dian { width: 0.17rem; height: 0.15rem; border-top: 1px solid black; border-bottom: 1px solid black; display: flex; align-items: center; span { display: inline-block; width: 100%; height: 1px; background-color: black; } } } .back { width: 0.4rem; height: 0.4rem; text-align: center; line-height: 0.4rem; background-color: rgba(0, 0, 0, 0.1); position: fixed; bottom: 0.4rem; right: 0.15rem; font-size: 0.17rem; } .bottom { color: rgba(0, 0, 0, 0.44); font-size: 0.12rem; text-align: center; margin: 0.4rem 0 0.1rem; } } </style>
列表页代码:
<template> <div class="box"> <div class="HomeTitle"> <h1>AlloyTeam</h1> <p>腾讯全端 AlloyTeam 团队 Blog</p> </div> <ul class="HomeList"> <!-- 循环 --> <li v-for="item in list" :key="item.id"> <!-- 文章标签 数组转换为字符串 --> <p class="web">{{ item.tags.toString() }}</p> <!-- 标题,点击跳转到详情 --> <h1 class="title" @click="next(item.id)">{{ item.title }}</h1> <!-- 作者和图片 --> <span class="author"> <!-- <img :src="item.avatar" alt="" /> --> {{ item.author }} </span> <p class="separator"> <!-- 使用dayjs转换时间格式 --> {{ dayjs(item.date).format("YYYY-MM-DD") }} / <!-- 用正则方法获取浏览次数 --> {{ item.separator.match(/\d+/g).toString() }} 次浏览 </p> <!-- 概述 --> <p class="content">{{ item.summary }}</p> </li> </ul> <div class="bottom"> <!-- 跳转到上一页 --> <router-link :to="{ name: 'HomeOne', query: { id: this.id } }" class="next" v-show="nextds" ><button @click="nextd">上一页</button></router-link > <!-- 跳转到下一页 --> <router-link :to="{ name: 'HomeOne', query: { id: this.id } }" class="next" v-show="nextss" ><button @click="nexts">下一页</button></router-link > </div> </div> </template> <script> export default { data() { return { list: [], id: localStorage.getItem("id") || [1], nextds: false, nextss: true, }; }, created() { localStorage.setItem("id", this.id); // 进入时直接调用 axios 接口 this.request(); // 进入时直接调用 上下页按钮是否显示 this.click(); }, methods: { nexts() { // 页数加一 this.id++; // 存储至本地 localStorage.setItem("id", this.id); // 调用 axios 请求 this.request(); // 调用上下页按钮是否显示 this.click(); // 回到顶部 document.documentElement.scrollTop = 0; }, // 上一页 nextd() { // 页数减一 this.id--; // 存储至本地 localStorage.setItem("id", this.id); // 调用 axios 请求 this.request(); // 调用上下页按钮是否显示 this.click(); // 回到顶部 document.documentElement.scrollTop = 0; }, // 点击上下页按钮是否显示 click() { // 判断上一页点击按钮是否显示 this.id >= 2 ? (this.nextds = true) : (this.nextds = false); // 判断下一页点击按钮是否显示 this.id >= 3 ? (this.nextss = false) : (this.nextss = true); }, request() { // axios 请求 页面1,每个页面5个 this.$axios .get(`/api/articles?page=${localStorage.getItem("id")}&limit=5`) .then(({ data }) => { console.log(data.results); // 请求的值赋值给list this.list = data.results; }); }, // 点击进入详情 next(id) { // console.log(id); this.$router.push({ name: "Details", query: { id: id }, }); }, }, }; </script> <style lang="scss" scoped> .box { width: 100%; height: 100%; .HomeTitle { width: 100%; // height: 2rem; margin: 0.6rem 0; // background-color: pink; text-align: center; overflow: hidden; h1 { font-size: 0.41rem; margin: 0 0 0.1rem; } p { font-size: 0.14rem; color: #818181; text-transform: uppercase; letter-spacing: 0.02rem; } } .HomeList { li { padding: 0.15rem; text-align: center; border-bottom: 1px solid #f2f2f2; .web { font-size: 0.1rem; color: #c39f76; text-transform: uppercase; letter-spacing: 0.02rem; } .title { font-size: 0.2rem; margin: 0.13rem 0; } .author { color: #939393; } .separator { margin: 0.12rem 0; font-size: 0.1rem; color: #939393; } .content { margin: 0.12rem 0 0.13rem; text-align: left; color: rgba(0, 0, 0, 0.7); display: -webkit-box; //对象作为弹性伸缩盒子模型显示 overflow: hidden; //溢出隐藏 -webkit-box-orient: vertical; //设置伸缩盒子对象的子元素的排列方式 -webkit-line-clamp: 3; //设置 块元素包含的文本行数 } } } .bottom { margin: 0.15rem; position: relative; .next:first-child { position: absolute; left: 0; } .next:last-child { position: absolute; right: 0; } } } </style>
列表页分页效果
看 axios 的页数显示显示几页 按页数判断上下页按钮是否显示 并把页数保存至本地
详情页代码:
<template> <div class="box"> <!-- 文章标签 数组转换为字符串 --> <p class="web">{{ list.tags.toString() }}</p> <!-- 标题 --> <h1 class="title">{{ list.title }}</h1> <!-- 图片和作者 --> <span class="author"> <!-- <img :src="list.avatar" alt="" /> --> {{ list.author }} </span> <!-- 使用dayjs转换时间格式 --> <p class="separator"> {{ dayjs(list.date).format("YYYY-MM-DD") }} / <!-- 用正则方法获取浏览次数 --> {{ list.separator.match(/\d+/g).toString() }} 次浏览 </p> <!-- 内容,里面有其他标签使用v-html输出 --> <p v-html="list.content" class="content"></p> </div> </template> <script> export default { data() { return { list: [], }; }, created() { // 进入时直接调用 this.request(); }, methods: { request() { // axios 请求 点击列表的详情 this.$axios .post(`/api/articles/${this.$route.query.id}`) .then(({ data }) => { console.log(data); // 请求到的值赋值给list this.list = data; }); }, }, }; </script> <style lang="scss" scoped> .box { text-align: center; .content { text-align: left; padding: 0.44rem 0.15rem 0; overflow: hidden; img { display: inline-block; width: 3.75rem; } } .web { font-size: 0.1rem; color: #c39f76; text-transform: uppercase; letter-spacing: 0.02rem; } .title { font-size: 0.2rem; margin: 0.13rem 0; } .author { color: #939393; } .separator { margin: 0.12rem 0; font-size: 0.1rem; color: #939393; } } </style>
以上就是AlloyTeam(腾讯全端博客)的代码,不懂得也可以在评论区里问我,以后会持续添加一些新的功能,敬请关注。