头条APP
1.项目介绍:
- 头条(极客园)移动端是一个IT资讯移动web应用,有着和今日头条类似的资讯浏览体验。
- 主要功能:资讯列表、标签页切换,文章举报,频道管理、文章详情、关注功能、点赞功能、评论功能、搜索功能、登录功能、个人中心、编辑资料、小思同学
- 头条可打包成一款移动APP,后期结合H5+可在Dcloud打包成一款体验较好的手机应用。
2.项目技术点介绍
-
vuejs中
- $nextTick使用 (vue更新DOM是异步的)
- 组件通信 (父, 子传递)
- async和await用法
- keep-alive 组件缓存
-
vuex
- actions中发ajax请求
- actions的返回值问题
-
vue-router
- 懒加载 (对打包以后首页加载速度有提高)
-
axios
- 请求和响应拦截器
- 封装请求工具方法 (代码分层)
-
vant
- 对组件使用更熟悉
- 掌握使用和查阅文档的能力
-
socket.io-client
- http协议复习 (请求报文和响应报文)
- 与ajax区别
- ajax和socket之间的选择
-
amfe-flexible
- 移动端rem适配
3.项目分析
- 1首先开发登录注册页面
- 2登录后首页,以及默认展示的页面,组件间通信,数据获取,day.js的使用(多翻文档,很多方法都封装好了)
- 3遇到一个大坑,父子间通信props接收的名字一定不要错!!!!!!
- 4 vue中use的用法--封装一个自动聚焦方法 [Vue.use相关文档: cn.vuejs.org/v2/api/#Vue…]
- 搜索关键字高亮的方法----注意:模板字符串中修改样式要用
v-html
// 搜索关键字高亮
lightFn (originStr, target) {
// originStr:原来字符串
// target:关键字
return originStr.replace(target, `<span style="color: red;">${target}</span>`)
}
<!-- 搜索建议列表 -->
<div class="sugg-list">
<div class="sugg-item" v-for="(str, index) in searchList" :key="index" v-html="lightFn(str, value)" >
搜索建议
</div>
</div>
- 保存搜索历史
watch: {
// 因为跳转页面, 原来页面被释放了, 回来后数组重新创建
// 解决: 本地缓存起来
// 问题2: 但是发现跳转后, 并未保存到本地(==原因: 先跳转了, watch还未来的及执行==)
// 解决: 给路由跳转加个定时器(最后执行)
history () {
localStorage.setItem('his', JSON.stringify(this.history))
}
},
methods: {
// 跳转到搜索结果页
onSearch (val) {
this.history.push(val) // 保存搜索关键字
setTimeout(() => {
this.$router.push(`/search/:${val}`)
})
}
- 首页文章列表有X符号,搜索结果页没有
// 在结果页组件中
:showX="false"
// 在首页组件中
props: {
showX: {
type: Boolean,
default: true
}
}
- 关于关注和取消关注
followedFn
<van-button type="info" plain size="mini" v-if="artObj.is_followed" @click="followedFn(false)">已关注</van-button>
<van-button icon="plus" plain type="info" size="mini" v-else @click="followedFn(true)">关注</van-button>
methods: {
// 作者关注/取关
async followedFn (bool) {
if (bool === true) {
// 业务: 关注用户
// 显示: 已关注按钮
this.artObj.is_followed = true
await followedUserAPI({
target: this.artObj.aut_id
})
} else {
// 业务: 不关注用户
// 显示: 已取消关注按钮
this.artObj.is_followed = false
await unFollowedUserAPI({
uid: this.artObj.aut_id
})
}
}
}
- 不需要循环的接口数据,在data接收后直接用就好啦
data () {
return {
// 请求数据, 保存到data变量上, 才能在vue模板标签上直接用
user: {}
}
}
- 更新用户头像
- 1点击图片,触发选择文件按钮(移花接木)
<van-image round class="avatar" :src="profile.photo" @click="$refs.iptFile.click()"/>
<input type="file" ref="iptFile" v-show="false" accept="image/*" @change="onFileChange">
- 调用api接口
// 用户- 更新头像
// 注意: formObj的值必须是一个表单对象
// '{"a": 10, "b": 20}' // 对象格式的JSON字符串
// new FormData() // 表单对象
export const updatePhotoAPI = (formObj) => {
return request({
url: '/v1_0/user/photo',
method: 'PATCH',
data: formObj
// 如果你的请求体内容是表单对象, 浏览器会自动携带请求头Content-Type为multipart/form-data
})
}
- 3更新头像--前端如何创建表单对象?
- new FormData
methods: {
async onFileChange (e) {
// console.log(e.target.files[0])
if (e.target.files[0].length === 0) return // 防止用户未选择图片
const fd = new FormData()
fd.append('photo', e.target.files[0]) // photo在表单里参数名携带
const res = await updatePhotoAPI(fd)
console.log(res)
this.profile.photo = res.data.data.photo
}
websocket实现聊天机器人
步骤:
1.安装客户端socket的包(支持websocket) - 内部对websocket进行了封装
yarn add socket.io-client@4.0.0
2.在Chat/index.vue引入包
// 导入 socket.io-client 包
import { io } from 'socket.io-client'
// 定义变量,存储 websocket 实例
let socket = null
3.创建socket服务
created() {
// ...
// 创建客户端 websocket 的实例
socket = io('http://toutiao.itheima.net', {
query: {
token: this.token
},
transports: ['websocket']
})
}
4.监听是否连接成功--只有连接内置事件执行了, 才能进行后续操作
created() {
// 建立连接的事件
socket.on('connect', () => {
console.log('与服务器建立了连接')
})
}
5在组件销毁前, 关闭服务
// 组件被销毁之前,清空 sock 对象
beforeDestroy() {
// 关闭连接
socket.close()
// 销毁 websocket 实例对象
socket = null
},
6在created监听socket的消息
created() {
// ...
// 接收到消息的事件
socket.on('message', data => {
// 把服务器发送过来的消息,存储到 list 数组中
this.list.push({
name: 'xs',
msg: data.msg
})
})
},
7在 send事件中, 把服务器发来的数据装到数组里
sendFn () {
// 判断内容是否为空
if (!this.word) return
// 添加聊天消息到 list 列表中
this.list.push({
name: 'me',
msg: this.word
})
}
8客户端调用 socket.emit('message', 消息内容) 方法把消息发送给 websocket 服务器:
// 向服务端发送消息
sendFn () {
// 判断内容是否为空
if (!this.word) return
// 添加聊天消息到 list 列表中
this.list.push({
name: 'me',
msg: this.word
})
// 把消息发送给 websocket 服务器
socket.emit('message', {
msg: this.word,
timestamp: new Date().getTime()
})
// 清空文本框的内容
this.word = ''
}
- 路由懒加载--使用
component: Login
// 改成这个写法
component: () => import('@/views/Login.vue')
路由拦截器, 可以让页面不上来都被引入到webpack里一起打包插入到浏览器运行
等待使用时, 再去循环对应页面组件
-
为何使用路由拦截器?
- 为了让首页渲染更快
-
什么是路由懒加载?
- 路由规则匹配后, 再加载对应js代码
- 路由懒加载后,编辑个人资料不会立即刷新。解决办法,将更新后的数据存到vuex中,映射更新
路有缓存(大坑)
实现部分路由缓存,部分路由不缓存(打开刷新),在一级路由中使用keep-alive,使用include包含或者exlude去除来决定需要或不需要缓存的组件!!!
<!-- exclude 的值要与组件的name一致,而不是路由的名字!!! -->
<keep-alive :exclude="['ArticleDetail', 'MyLogin', 'MySearch', 'SearchResult']">
<router-view/>
</keep-alive>