项目分析六

一、文章详情——创建组件并配置路由

// 1.创建文件,src/views/article/index.vue

// 2.在src/router/index.vue中将文章详情页配置到一级路由 const routes = [ ..... { path: '/article/:articleId', name: 'article', component: () => import('@/views/article'), props: true,// 动态路径参数的解耦:将路由动态参数映射到组件的 props 中,更推荐这种做法 } ];

// 3.配置跳转路由,在src/components/article-item/index.vue中

// 4.页面布局 .article-container { .main-wrap { position: fixed; left: 0; right: 0; top: 92px; bottom: 88px; overflow-y: scroll; background-color: #fff; } .article-detail { .article-title { font-size: 40px; padding: 50px 32px; margin: 0; color: #3a3a3a; }.user-info { padding: 0 32px; .avatar { width: 70px; height: 70px; margin-right: 17px; } .van-cell__label { margin-top: 0; } .user-name { font-size: 24px; color: #3a3a3a; } .publish-date { font-size: 23px; color: #b7b7b7; } .follow-btn { width: 170px; height: 58px; } }.article-content { padding: 55px 32px; /deep/ p { text-align: justify; } } }.loading-wrap { padding: 200px 32px; display: flex; align-items: center; justify-content: center; background-color: #fff; }.error-wrap { padding: 200px 32px; display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: #fff; .van-icon { font-size: 122px; color: #b4b4b4; } .text { font-size: 30px; color: #666666; margin: 33px 0 46px; } .retry-btn { width: 280px; height: 70px; line-height: 70px; border: 1px solid #c3c3c3; font-size: 30px; color: #666666; } }.article-bottom { position: fixed; left: 0; right: 0; bottom: 0; display: flex; justify-content: space-around; align-items: center; box-sizing: border-box; height: 88px; border-top: 1px solid #d8d8d8; background-color: #fff; .comment-btn { width: 282px; height: 46px; border: 2px solid #eeeeee; font-size: 30px; line-height: 46px; color: #a7a7a7; } .van-icon { font-size: 40px; .van-info { font-size: 16px; background-color: #e22829; } } } }

二、获取文章数据
// 1.封装请求,在src/api/article.js中 export const getArticleById = (articleId) => { return request({ method: 'GET', url: `/v1_0/articles/${articleId}`, }) };

// 2.获取文章信息,在src/views/article/index.vue中 // 2.1.导入请求方法 import { getArticleById } from '@/api/article'export default { name: 'ArticlePage', components: {}, props: { articleId: { type: String, required: true } }, data () { return { article: {} // 2.2.定义变量来储存数据 } }, computed: {}, watch: {}, created () { // 2.4. 调用方法 this.loadArticle() }, mounted () {}, methods: { // 2.3. 定义获取数据请求方法 async loadArticle () { try { // 2.3.1 发送请求 const { data } = await getArticleById(this.articleId) console.log(data) // 2.3.3 成功赋值 this.article = data.data console.log(this.article) } catch (err) { // 2.3.2 失败处理 console.log(err) this.$toast("获取数据失败"); } } } }

// 3.渲染数据到页面{{ article.title }}

三、处理加载情况
// 1. 在src/views/article/index.vue中的data中定义变量data() { return { ... loading: true, // 加载中的 loading 状态 errStatus: 0, // 失败的状态码 }; },

// 2.在src/views/article/index.vue中 async loadArticle () { // 2.1 展示 loading 加载中 this.loading = true try { const { data } = await getArticleById(this.articleId)// if (Math.random() > 0.5) { //JSON.parse('dsankljdnskaljndlkjsa') // }// 赋值 this.article = data.data} catch (err) { if (err.response && err.response.status === 404) { this.errStatus = 404 } } // 2.2无论成功还是失败,都需要关闭 loading this.loading = false },

// 3.在在src/views/article/index.vue中判断 ... ... ... ...

四、处理内容的样式
// 1. 将github-markdown-css样式文件放到src/views/article中,与index.vue同级// 2.在src/views/article/index.vue中引用@import "./github-markdown.css"; ....// 3.添加到标签中 正文结束

// 4.postcss.config.js文件中添加忽略 module.exports = { plugins: {.... propList: ['*'], // 配置不要转换的样式资源 exclude: 'github-markdown'// 添加忽略文件 } } }// 5.注意,一定要重启项目,否则不会起作用

五、点击图片预览
// 1. 使用vant组件库中的 ImagePreview 图片预览 组件// 2. 增加ref属性, 在src/views/article/index.vue中// 3.导入ImagePreview 图片预览 组件插件,在src/views/article/index.vue中 import { ImagePreview } from 'vant' // 4. methods: { async loadArticle() { this.loading = true; try { const { data } = await getArticleById(this.articleId); // console.log(data); data.data.content = data.data.content.replaceAll('https://images.weserv.nl/?url=','') this.article = data.data; // 初始化图片点击预览 console.log(this.$refs["article-content"]); // 这里没有内容 // 这个时候其实找不到 这个refs引用的,原因是因为v-if的渲染其实需要时间,我们视图还没有立即更新完成。 // 使用定时器,延迟更新( setTimeout 0 会把要做的事情放在异步队列的最后面执行! ) setTimeout(() => { console.log(this.$refs["article-content"]); // 这里有内容 this.previewImage(); }, 0); } catch (err) { // this.$toast("获取数据失败"); if (err.response && err.response.status === 404) { this.errStatus = 404; } } this.loading = false; }, previewImage() { // 得到所有的 img 节点 const articleContent = this.$refs["article-content"]; // 获取到了容器节点 const imgs = articleContent.querySelectorAll("img"); // 获取所有 img 地址 const images = []; imgs.forEach((img, index) => { images.push(img.src); // 给每个 img 注册点击事件,在处理函数中调用预览 img.onclick = () => { ImagePreview({ // 预览的图片地址数组 images, // 起始位置,从 0 开始 startPosition: index, }); }; }); }, },

【项目分析六】

    推荐阅读