一、首页的一个搜索框
===我们可以直接用van-nav-bar里面直接加入一个button,button的插槽slot定义为titie的话就可以制作一个居中的button了
一般通过F12来进行测试得到的class的话,而不是代码里面定义的class的话,一般都氏可以通过/deep/来深入到这种vue框架内部定义的class了
====一般图标的大小定义的话,可以直接通过font-size。而不是像图片一样通过width和height
<van-tabs v-model="active"> <van-tab title="标签 1">内容 1</van-tab> <van-tab title="标签 2">内容 2</van-tab> <van-tab title="标签 3">内容 3</van-tab> <van-tab title="标签 4">内容 4</van-tab> <van-tab title="标签 5">内容 5</van-tab> </van-tabs> <!-- /文章频道列表 -->
通过tab频道栏,通过active氏哪个数字以及v-model来表示tabs中的哪个tab就可以被激活呢?
<van-tabs v-model="active"> <van-tab :title="channel.name" v-for="channel in channels" :key="channel.id" > {{ channel.name }}的内容 </van-tab> </van-tabs>
如果是把data里面的数据进行渲染的话,一般都是通过“:”就是要用来绑定我们的属性title和key了
文章列表
利用组件来处理。
具体做法就是:
- 封装一个文章列表组件
- 然后在频道列表中把文章列表遍历出来
===因为文章列表组件中请求获取文章列表数据需要频道 id,所以 频道 id 应该作为 props 参数传递给文章列表组件,
为了方便,我们直接把频道对象传递给文章列表组件就可以了。
为什么标签内容是懒渲染的?
<template> <div class="article-list"> <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" > <van-cell v-for="item in list" :key="item" :title="item" /> </van-list> </div> </template> <script> export default { name: 'ArticleList', components: {}, props: { channel: { type: Object, required: true } }, data () { return { list: [], loading: false, finished: false } }, computed: {}, watch: {}, created () {}, mounted () {}, methods: { onLoad () { // 异步更新数据 // setTimeout 仅做示例,真实场景中一般为 ajax 请求 setTimeout(() => { for (let i = 0; i < 10; i++) { this.list.push(this.list.length + 1) } // 加载状态结束 this.loading = false // 数据全部加载完成 if (this.list.length >= 40) { this.finished = true } }, 1000) } } } </script> <style scoped lang="less"></style>
因为这是 Tab 标签页组件本身支持的默认功能,如果不需要可以通过配置 :lazy-render="false"
来关闭这个效果。
===当组件初始化或滚动到到底部时,会触发 load 事件并将 loading 设置成 true,此时可以发起异步操作并更新数据,数据更新完毕后,将 loading 设置成 false 即可。
若数据已全部加载完毕,则直接将 finished 设置成 true 即可。
让文章列表固定
.article-list { position: fixed; left: 0; right: 0; top: 90px; bottom: 50px; overflow-y: auto; }
import { getArticles } from '@/api/article' export default { name: 'ArticleList', components: {}, props: { channel: { type: Object, required: true } }, data () { return { articles: [], // 数据列表 loading: false, // 控制加载中的 loading 状态 finished: false, // 控制加载结束的状态,当加载结束,不再触发加载更多 timestamp: null // 获取下一页数据的时间戳 } }, computed: {}, watch: {}, created () {}, mounted () {}, methods: { async onLoad () { console.log('onLoad') // 1. 请求获取数据 const { data } = await getArticles({ channel_id: this.channel.id, // 频道 ID timestamp: this.timestamp || Date.now(), // 时间戳,请求新的推荐数据传当前的时间戳,请求历史推荐传指定的时间戳,timestamp 相当于页码,请求最新数据使用当前最新时间戳,下一页数据使用上一次返回的数据中的时间戳 with_top: 1 // 是否包含置顶,进入页面第一次请求时要包含置顶文章,1-包含置顶,0-不包含 }) // 2. 把数据放到 list 数组中 const { results } = data.data this.articles.push(...results) // 3. 设置本次加载状态结束,它才可以判断是否需要加载下一次,否则就会永远的停在这里 this.loading = false // 4. 数据全部加载完成 if (results.length) { // 更新获取下一页数据的页码 this.timestamp = data.data.pre_timestamp } else { // 没有数据了,把加载状态设置结束,不再触发加载更多 this.finished = true } } } }
下拉刷新
这里主要使用到 Vant 中的 PullRefresh 下拉刷新 组件。
基本使用和属性
<van-pull-refresh v-model="isRefreshLoading" :success-text="refreshSuccessText" :success-duration="1500" @refresh="onRefresh" >
下拉刷新时会触发组件的 refresh
事件,在事件的回调函数中可以进行同步或异步操作,操作完成后将 v-model
设置为 false
,表示加载完成。
this.articles.unshift(
这个代码就是把更新的东西放到数组的顶部了
文章列表项
封装组件
在我们项目中有好几个页面中都有这个文章列表项内容,如果我们在每个页面中都写一次的话不仅效率低而且维护起来也麻烦。所以最好的办法就是我们把它封装为一个组件,然后在需要使用的组件中加载使用即可。
创建 src/components/article-item/index.vue
组件
关于第三方图片资源403问题
如何设置不发送 referrer?
用 <a>
、<area>
、<img>
、<iframe>
、<script>
或者 <link>
元素上的 referrerpolicy
属性为其设置独立的请求策略,例如:
<img src="http://……" referrerPolicy="no-referrer">
或者直接在 HTMl 页面头中通过 meta 属性全局配置:
<meta name="referrer" content="no-referrer" />
处理相对时间
推荐两个第三方库:
两者都是专门用于处理时间的 JavaScript 库,功能差不多,因为 Day.js 的设计就是参考的 Moment.js。但是 Day.js 相比 Moment.js 的包体积要更小一些,因为它采用了插件化的处理方式。
Day.js 是一个轻量的处理时间和日期的 JavaScript 库,和 Moment.js 的 API 设计保持完全一样,如果您曾经用过 Moment.js, 那么您已经知道如何使用 Day.js 。
import Vue from 'vue' import dayjs from 'dayjs' // 加载中文语言包 import 'dayjs/locale/zh-cn' import relativeTime from 'dayjs/plugin/relativeTime' // 配置使用处理相对时间的插件 dayjs.extend(relativeTime) // 配置使用中文语言包 dayjs.locale('zh-cn') // 全局过滤器:处理相对时间 Vue.filter('relativeTime', value => { return dayjs().from(dayjs(value)) })