一进入home组件 就去cookie中获取用户信息username 如果能获取到 就带着username调用后端的接口userInfo,userInfo去数据库中取用户信息并返回,前端从用户信息中取出头像的src绑定到avatar变量上,然后动态赋值给img的src
mounted() {
this.username = getInfo();
if (this.username) {
userInfo().then((response) => {
this.avatar = response.data.data.avatar;
})
}
}
getInfo() {
return vue.$cookies.get(userInfo);
}
userInfo(data){//获取用户信息
let req = {
data,
url: 'admin/user_info'
}
return _get(req);
}
_get(req){
return axios.get(req.url, {params: req.data})
}
在vue中如果想要操作cookie,可以使用vue-cookies
插件:
- 安装:在终端输入
npm install vue-cookies --save
- 在
main.js
中引入并使用:
import VueCookies from 'vue-cookies'
Vue.use(VueCookies)
- 设置全局配置:
$cookies.config(expireTimes[,path[, domain[, secure[, sameSite]]])
默认为:expireTimes = 1d, path = '/', domain = '', secure = '', sameSite = 'Lax'
- 设置cookie;
$cookies.set(keyName, value[, expireTimes[, path[, domain[, secure[, sameSite]]]]]) //return this
- 获取cookie:
$cookies.get(keyName) // return value
- 删除cookie:
$cookies.remove(keyName [, path [, domain]]) // return this
- 判断是否存在某个cookie:
$cookies.isKey(keyName) // return false or true
- 获取所有cookie:
$cookies.keys() // return a array
顶部导航条:复用head组件
用户信息
上传图片逻辑:
- avatar中绑定默认图片的地址 然后赋值给img的src 展示默认图片
- label标签将头像和隐藏的表单元素包起来 使用for属性绑定输入框的 当点击label标签的内容时 会触发绑定的隐藏的input 上传文件
- 当输入框的值和上一次的值不同 会触发input的change事件 此时判断
(1)input里的file是否有值 因为input里的file如果被清除,change事件也会被触发
(2)选择的文件是不是图片
(3)限制图片的大小 - 开始上传前先开启loading组件 给用户好的体验
- 调用后端的接口 获取七牛云上传凭证
- 若没获取到 使用alertTip组件弹出错误信息
- 获取到了之后将图片和凭证以键值对的形式存在FormData中 使用post方法上传到七牛云仓库 设置
withCredentials:false
禁止携带cookie - 上传成功后 七牛云会返回前端图片在网上的url 把url赋值给img的src 展示用户上传的头像 并调用后端的接口 将该url保存在数据库中
- 停止loading组件的展示
<div id="user-info">
<!--
使用label标签将头像和隐藏的表单元素包起来 就可以实现点击头像上传图片 使用for属性绑定输入框的
当点击label标签的内容时 会触发绑定的隐藏的input 上传文件
当输入框的值和上一次的值不同 且输入框失去焦点时 会触发change事件 调用fileUpload上传文件
-->
<label class="avatar" for="file">
<img :src="avatar">
<input id="file" type="file" @change="fileUpload($event)" style="display: none;">
</label>
<!-- username为null 显示登录/注册 点击可跳转到登录/注册组件 -->
<router-link v-if="!username" class="login" to="/login">登录/注册</router-link>
<!--username不为null 则显示username-->
<span v-else class="username">{{username}}</span>
</div>
<script>
fileUpload(event) {
let file = event.target.files[0];
// change事件里面一定要检测input里的file是否有值,因为input里的file如果被清除,change事件也会被触发。
// 但是这里不检测也没事 所以下面检测是否有值的代码被注释了
if (!file || file.length === 0) {
return;
}
let fileName = file.name;
let fileType = fileName.substr(fileName.lastIndexOf(".")).toUpperCase();
if (fileType !== ".GIF" && fileType !== ".PNG" && fileType !== ".JPG" && fileType !== ".JPEG") {
// 判断选择的文件是不是图片
this.alertText = '请选择图片文件!';
this.showTip = true;
}else if (file.size > 1024 * 1024 * 3) {// 只能传2M以内照片
this.alertText = '上传失败,只能传2M以内图片'
this.showTip = true;
} else {
// 调用后端的接口 获取七牛云上传凭证response.data.uptoken
this.loading = true;
uploadToken().then((response) => {
if (response.data.status === 200) {
let data = {token: response.data.uptoken, file}
// 带着上传凭证上传图片到七牛云
upload(data).then((upResponse) => {
let pic_url = config.domain + upResponse.data.key
this.avatar = pic_url;// 把从七牛云那里得到的图片的网络地址赋值给头像的src
this.loading = false;
changeAvatar({pic_url}).then(() => {
})//更新到数据库
})
} else {
this.alertText = response.data.message
this.showTip = true;
}
})
}
}
uploadToken = (data) => {
let req = {data,url: 'service/uploadtoken'};
return _get(req);
}
_get(req){
returnh axios.get(req.url, {params: req.data})
}
upload(data){
/*
将上传凭证和图片保存在FormData中发送给七牛云 使用post发送 withCredentials设为false 禁止携带cookie
FormData提供了一种表示表单数据的键值对的构造方法 可以将数据通过XMLHttpRequest.send()发送出去
Object.keys(data)得到data对象的键组成的数组
*/
let formData = new FormData();
Object.keys(data).forEach(key => {
formData.append(key, data[key])// 向FormData中添加新数据
})
let req = {data: formData,url: '/upload-z2.qiniup.com/'}
return _postNoWithCredentials(req);
}
// post and no withCredentials 访问七牛云服务器使使用这个方法
// 访问七牛云时 为了安全 不把cookie带过去 withCredentials:false禁止跨域携带cookie
_postNoWithCredentials(req){
return axios({
method: 'post',
url: `/${req.url}`,
data: req.data,withCredentials:false
})
}
//改变用户头像
changeAvatar(data){
let req = {
data,
url: 'admin/change_avatar'
}
return _post(req)
}
_post(req){
return axios({
method: 'post',
url: `/${req.url}`,
data: req.data
})
}
</script>
兴趣栏
遍历data中的数组myFunList 将数据展示出来 监听点击 点击后跳转到相应的组件 使用路由实现
<ul>
<li v-for="(item,index) in myFunList" :key="index" @click="routerChange(item.url)">
<div class="img-wrap">
<img :src="item.picUrl">
</div>
<span>{{item.name}}</span>
</li>
</ul>
<script>
myFunList: [
{
url: '/home/collection',
picUrl: 'http://p1.meituan.net/50.0.100/xianfu/9c1388ba5fbb367c1a93996f39c2fba94506.jpg',
name: '我的收藏'
},
...
]
routerChange(url) {
if (this.username) {
this.$router.push(url);
} else {
this.$router.push('/login');
}
}
</script>
我的收藏
顶部导航栏:复用head组件 中间就展示了一张图片和字
<div class="info-container">
<img src="../../../assets/nothing.png">
<span class="text">没有收藏的你一定是个假吃货</span>
</div>
我的足迹
顶部导航栏:复用head组件 中间就展示了一张图片和字
<div class="info-container">
<img src="../../../assets/nothing.png">
<span class="tip">漫漫美食路,一个脚印也没留下</span>
<p class="text">美食排着队 等你去品尝</p>
</div>
我的评价
顶部导航栏:复用head组件
组件一创建 就发送get请求给后端 后端去数据库中获取用户信息 保存在userInfo中、该用户的所有评论 保存在commentList中
created() {
userInfo().then((response) => {
let res = response.data;
if (res.status === 200) {
this.userInfo = res.data;
}
})
comment().then((response) => {
let res = response.data;
if (res.status === 200) {
this.commentList = res.data;
}
})
}
userInfo(data){//获取用户信息,后端拿着用户id查询数据库
let req = {data,url: 'admin/user_info'}
return _get(req);
}
comment(data){//获取我的评论,后端拿着用户id查询数据库
let req = {data,url: 'v1/my_comment'}
return _get(req);
}
_get(req){
returnh axios.get(req.url, {params: req.data})
}
若commentList中没有评论(该用户没有评论)则显示一张图片和一行字(如上图) 通过v-show来控制他们的显示与隐藏
<div class="empty-container" v-show="!commentList.length">
<img src="../../../assets/nothing.png">
<span class="text">没有任何评论哦</span>
</div>
否则从userInfo中获取用户的头像、昵称、评论数显示出来 v-show来控制他们的显示与隐藏
<div class="userinfo" v-show="commentList.length">
<div class="avatar">
<img :src="userInfo.avatar">
</div>
<h3 class="username">{{userInfo.username}}</h3>
<span class="comment-count">已贡献{{commentList.length}}条评论</span>
</div>
遍历commentList中的内容 并展示出来 有一个点击删除的按钮 点击后会调用deleteComment方法:调用后端的接口删除数据库中的数据 然后前端删除commentList中相应的数据
deleteComment(id, index) {
deleteComment({id}).then((response) => {
if (response.data.status === 200) {
this.alertText = '删除成功';
this.showTip = true;
this.commentList.splice(index, 1)
} else {
this.alertText = '删除失败';
this.showTip = true;
}
})
}
deleteComment(data){
let req = {data,url: 'v1/comment'}
return _delete(req);
}
我的好友
顶部导航栏:复用head组件 按钮上面全是字和图 按钮和微信图标都是iconfont 下面的勾选同意:
<div class="allow-item">
<!--√-->
<span class="selected" v-if="allowItem" @click="allowItem=false;"><i class="iconfont"></i></span>
<!--圈-->
<span class="select" v-else @click="allowItem=true;"></span>
<span class="text">同意 <<strong>信息授权使用协议</strong>< </span>
</div>
圈和√是两个iconfont v-if控制√的显示与隐藏 allowItem默认为true 即一开始是勾选的 监听到√的点击后 allowItem变为false 隐藏√ 展示圈 监听到圈的点击后 allowItem变为true 展示√
答谢记录
顶部导航栏:复用head组件 中间就展示了一张图片和字
<div class="info-container">
<img src="../../../assets/nothing.png">
<span class="tip">没有答谢记录呢</span>
<p class="text">一分也是爱,一角也是情</p>
</div>
我的地址
组件一创建 就去调用后端接口,后端接口会拿着用户id查询数据库,获取所有地址信息并返回给前端,前端保存数据 并把第一条数据的id保存在selectAddressId 代表当前被选中的数据的id
created() {
getAllAddress().then((response) => {
this.addressLists = response.data.address;
this.selectAddressId = this.addressLists[0].id;
})
}
顶部导航栏复用head组件 v-show控制右边管理/完成的切换 点击后更改status
<nav>
<span>我的收货地址</span>
<span v-show="!status" @click="managerAddress()">管理</span>
<span v-show="status" @click="finish()">完成</span>
</nav>
<script>
managerAddress() {
this.status = true;
},
finish() {
this.status = false;
}
</script>
当点击管理后 展示出来的地址 右边会出现个iconfont 点击后可以删除该地址 v-show控制这个iconfont的展示与隐藏 当上面展示“完成”时 展示这个iconfont 点击这个iconfont后 会带着地址在数据库中的id去调用后端的接口deleteAddress删除这个地址 成功后再根据索引index删除addressLists中的这个地址
<i class="iconfont delete" v-show="status" @click="deleteAddress(item.id,index)"></i>
<script>
deleteAddress(id, index) {
deleteAddress({address_id: id}).then((response) => {
if (response.data.status === 200) {
this.addressLists.splice(index, 1); //通过splice 删除数据
}
})
}
deleteAddress(data){
let req = {data,url: 'admin/address'}
return _delete(req)
}
_delete(req){
return axios({method: 'delete', url: `/${req.url}`, data: req.data})
}
</script>
我的资产栏
遍历data中的数组myAssetsList 将数据展示出来
<ul>
<li v-for="(item,index) in myAssetsList" :key="index">
<div class="img">
<img :src="item.picUrl">
</div>
<span>{{item.name}}</span>
</li>
</ul>
<script>
myAssetsList: [
{
name: '红包',
picUrl: 'http://p1.meituan.net/50.0.100/xianfu/a361ce97f9f00f2715bb960a789d925e2315.jpg',
},
...
]
</script>
下面有个新增收货地址的按钮 点击后
更多推荐
遍历data中的数组introList 将数据展示出来
<ul>
<li v-for="(item,index) in introList" :key="index">
<div class="img">
<img :src="item.picUrl">
</div>
<span>{{item.name}}</span>
</li>
</ul>
<script>
introList: [
{
picUrl: 'http://p0.meituan.net/50.0.100/xianfu/cf5ddfcae114ed8d7d147d51064532252477.jpg',
name: '邀请有奖'
},
...
]
</script>