1. 做了什么:登录模块、频道模块、搜索模块、文章模块、评论模块、个人信息模块
2.具体使用的技术栈和操作步骤和问题解决:
(1)vue技术
创建vue项目
vue create toutiao-m
进行一些基本的配置,选择Manually select features
Babel、Router、Vuex、CSS Pre-processors、Linter / Formatter
n
Less
ESLint + Standard config
Lint on save、Lint and fix on commit
In dedicated config files
N
然后进入项目运行项目(yarn serve)
(2)vue-cli 利用脚手架创建项目
npm install --global @vue/cli
(3)vue-Router 配置路由
app.vue中写
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
]
const router = new VueRouter({
routes
})
export default router
layout页面采用路由懒加载
{
path: '/',
component: () => import('@/views/layout')
}
(4)iconfont(iconfont-阿里巴巴矢量图标库 )
创建一个新项目,点击添加‘上传图标到项目’
点击去除颜色并提交,生成在线链接,引入到项目中
(5)less 创建style文件夹,将图标的less文件写入到该文件中
(6)vant组件库
下载、这里用全局导入方式
button、cell、icon、image、popup、toast、field、grid、navbar、pullRefresh
(7)rem适配 postcss-pxtorem (将单位转化为rem)、lib-flexible 设置rem的基准值
)postcss-pxtorem 插件的配置
module.exports = {
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*']
}
}
}
rootValue
:表示根元素字体大小,它会根据根元素大小进行单位转换
propList
用来设定可以从 px 转为 rem 的属性
(8)axios
安装 axios
npm i axios
创建 src/utils/request.js
/** * 封装 axios 请求模块 */ import axios from "axios" const request = axios.create({ baseURL: "http://ttapi.research.itcast.cn/" // 基础路径 }) export default request
如何使用
方式一(简单方便,但是不利于接口维护):我们可以把请求对象挂载到 Vue.prototype
原型对象中,然后在组件中通过 this.xxx
直接访问
方式二(推荐):我们把每一个请求都封装成每个独立的功能函数,在需要的时候加载调用,这种做法更便于接口的管理和维护
(9) 本地存储localstroage
(10)返回的有token和refresh_token,
token
:访问令牌,有效期2小时
refresh_token
:刷新令牌,有效期14天,用于访问令牌过期之后重新获取新的访问令牌
token存在vuex容器中(比起子父组件传值,它更加方便),为了持久化,还需要本地储存
(11)接口封装请求方式:
import store from '@/store'
/**
* 获取用户自己的信息
*/
export const getUserInfo = () => {
return request({
method: 'GET',
url: '/app/v1_0/user',
// 发送请求头数据
headers: {
// 注意:该接口需要授权才能访问
// token的数据格式:Bearer token数据,注意 Bearer 后面有个空格
Authorization: `Bearer ${store.state.user.token}`
}
})
}
// vue文件中
import { getUserInfo } from '@/api/user'
(12)使用请求拦截器统一给Authorization 添加`Bearer token
`
// 请求拦截器
// Add a request interceptor
request.interceptors.request.use(function (config) {
// Do something before request is sent
// config :本次请求的配置对象
// config 里面有一个属性:headers
const { user } = store.state
if (user && user.token) {
config.headers.Authorization = `Bearer ${user.token}`
}
return config
}, function (error) {
// Do something with request error
return Promise.reject(error)
})
(13)loading和finished两个变量控制加载状态:组件初始化或滚动到到底部时,会触发 load 事件并将 loading 设置成 true,此时可以发起异步操作并更新数据,数据更新完毕后,将 loading 设置成 false 即可。若数据已全部加载完毕,则直接将 finished 设置成 true 即可。
(14) vuex
将用户的登录信息储存进store里面的state中,在mutation中用setUser将数据本地储存
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
// 用户的登录状态信息
user: JSON.parse(window.localStorage.getItem('TOUTIAO_USER'))
// user: null
},
mutations: {
setUser (state, user) {
state.user = user
window.localStorage.setItem('TOUTIAO_USER', JSON.stringify(user))
}
},
actions: {
},
modules: {
}
})
async onLogin () {
// const loginToast = this.$toast.loading({
this.$toast.loading({
duration: 0, // 持续时间,0表示持续展示不停止
forbidClick: true, // 是否禁止背景点击
message: '登录中...' // 提示消息
})
try {
const res = await login(this.user)
// res.data.data => { token: 'xxx', refresh_token: 'xxx' }
+ this.$store.commit('setUser', res.data.data)
// 提示 success 或者 fail 的时候,会先把其它的 toast 先清除
this.$toast.success('登录成功')
} catch (err) {
console.log('登录失败', err)
this.$toast.fail('登录失败,手机号或验证码错误')
}
// 停止 loading,它会把当前页面中所有的 toast 都给清除
// loginToast.clear()
}
(15)403问题的解决
403:我们项目的接口数据是后端通过爬虫抓取的第三方平台内容,而第三方平台对图片资源做了防盗链保护处理。
在index.html中添加
不发送referrer就能解决图片拒绝访问的问题(即403问题)
(16)用dayjs或者moment处理时间
参考官网进行配置
设置过滤器
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().to(dayjs(value))
})
使用
{{ 日期数据 | relativeTime }}
(17)防抖技术lodash,使用方法参照官网
(18)搜索关键词高亮
highlightText(text) {
const highlightStr = `${this.searchText}`;
// 正则表达式 // 中间的内容都会当作匹配字符来使用,而不是数据变量
// 如果需要根据数据变量动态的创建正则表达式,则手动 new RegExp
// RegExp 正则表达式构造函数
// 参数1:匹配模式字符串,它会根据这个字符串创建正则对象
// 参数2:匹配模式,要写到字符串中
const reg = new RegExp(this.searchText, 'gi');
// text.replace(/匹配的内容/gi, highlightStr)
return text.replace(reg, highlightStr);
}
(19)使用json-bigint处理大数字问题
之所以请求文章详情返回 404 是因为我们请求发送的文章 ID (article.art_id)不正确。
JavaScript 能够准确表示的整数范围在-2^53
到2^53
之间(不含两个端点),超过这个范围,无法精确表示这个值,这使得 JavaScript 不适合进行科学和金融方面的精确计算。
const jsonStr = '{ "art_id": 1245953273786007552 }'
console.log(JSON.parse(jsonStr)) // 1245953273786007600
// JSON.stringify()
// JSONBig 可以处理数据中超出 JavaScript 安全整数范围的问题
console.log(JSONBig.parse(jsonStr)) // 把 JSON 格式的字符串转为 JavaScript 对象
// 使用的时候需要把 BigNumber 类型的数据转为字符串来使用
console.log(JSONBig.parse(jsonStr).art_id.toString()) // 1245953273786007552
console.log(JSON.stringify(JSONBig.parse(jsonStr)))
console.log(JSONBig.stringify(JSONBig.parse(jsonStr))) // 把 JavaScript 对象 转为 JSON 格式的字符串转
用法试例如上
(20)409 昵称重复
(21)cropperjs获取blob对象
安装后引入
import 'cropperjs/dist/cropper.css'
import Cropper from 'cropperjs'
在mounted里配置
const cropper = new Cropper(image, {
viewMode: 1, // 只能在裁剪的图片范围内移动
dragMode: 'move', // 画布和图片都可以移动
aspectRatio: 1, // 裁剪区默认正方形
autoCropArea: 1, // 自动调整裁剪图片
cropBoxMovable: false, // 禁止裁剪区移动
cropBoxResizable: false, // 禁止裁剪区缩放
background: false // 关闭默认背景
})
获取blob
confirm () {
// console.log(this.cropper.getData())
this.cropper.getCroppedCanvas().toBlob(blob => {
console.log(blob)
})
}
3.总结
零散的知识汇编成项目,需要做到两点:1.优化代码(模块化,相同的方法先定义成函数,方法的封装),2.打印错误信息,在控制台查看方便找错
最后,要时时刻刻复制变量名,避免因为变量名引发的错误