组件控制
版心控制
使用组件插槽方法,将路由组件包裹起来,通过修改组件的样式来控制版心的大小:
<TheLayout>
<router-view></router-view>
</TheLayout>
TheLayout.vue
<template>
<div class="content">
<slot></slot>
</div>
</template>
<script setup></script>
<style scoped>
.content {
width: 80vw;
max-width: 1124px;
margin: 0 auto;
margin-top: 88px;
}
</style>
头像组件
TheAvatar.vue
<template>
<img :src="src || defaultAvatar" alt="#" class="avatar"/>
</template>
<script setup>
import defaultAvatar from "../assets/avatarDefault.png"
/**
* 因为头像在许多页面都要复用,所以采用这种方式自定义组件的参数,值得学习
*/
defineProps({
src:String,
width:{
type:Number,
default:34,
},
height:{
type:Number,
default:34
}
})
</script>
<style scoped>
.avatar {
width: v-bind(width + "px");
height: v-bind(height + "px");
border-radius: 50%;
background: #eee;
object-fit: cover;
object-position: top center;
}
</style>
- 引入了
defaultAvatar
作为默认头像的路径。 - 定义了组件的参数,包括
src
、width
和height
。 - 在模板中使用
<img>
标签来显示头像,通过:src
属性绑定了一个src
变量,如果src
变量不存在,则使用defaultAvatar
作为默认头像。
注意样式:
- 使用v-bind指令给元素的
width
属性和height
绑定动态值,该值为变量width
或height
的值加上"px
"。- 设置元素的对象适应方式为覆盖(cover),即保持宽高比例不变,将对象缩放到填满容器。
- 设置元素的对象位置为顶部居中
样式技巧
大量的grid布局,例如:
.postMeta {
display: grid;
grid-template-areas:
"avatar name actions"
"pubDate pubDate actions";
grid-template-columns: 42px 1fr 3fr;
row-gap: 6px;
.avatar {
grid-area: avatar;
}
.postPubDate {
grid-area: pubDate;
color: #9f9f9f;
font-size: 14px;
}
span {
}
.postPubDate {
}
}
- 使用
grid-template-areas
属性来定义网格布局的区域。 grid-template-columns: 42px 1fr 3fr;
它由三个值组成,用空格隔开。每个值代表一列的宽度。42px
:第一列的宽度为42像素。1fr
:第二列的宽度为剩余空间的1份。这里的“fr”是“fraction”的缩写,表示比例。3fr
:第三列的宽度为剩余空间的3份。同样,这里的“fr”表示比例。
- 在第一行定义了三个区域,分别是"
avatar
"、“name
"和"actions
”。 - 在第二行定义了三个区域,分别是"
pubDate
"、“pubDate
"和"actions
”。 - 这样就定义了一个2行3列的网格布局,每个区域的名称和位置都已经确定。
Vuex技巧
-
点赞和收藏功能实现:
//外部触发:@likeClick="$store.dispatch('toggleLike', post.id)" actions:{ async toggleFavor({ commit }, id) { const isFavor = await favorPost(id); commit("toggleFavor", { id, isFavor }); }, } mutations:{ /** * 1. 首先,根据给定的id参数,在状态state的列表list中找到对应的帖子post。 * 2. 如果isLike为true,表示要点赞该帖子,则将帖子的liked_bies属性加1。如果liked_bies属性不存在,则默认为0再加1,防止undefined + 1。 * 3. 如果isLike为false,表示要取消点赞该帖子,则将帖子的liked_bies属性减1。 * 4. 最后,将帖子的likedByMe属性设置为isLike的值。 */ toggleLike(state, { id, isLike }) { let post = [] if(state.searchResult.length){ post = state.searchResult.find((post) => post.id === id); }else{ post = state.list.find((post) => post.id === id); } if (isLike) { post.liked_bies = (post.liked_bies || 0) + 1; } else { post.liked_bies--; } post.likedByMe = isLike; }, }
工具包
很常见的时间显示风格的功能实现:
/**
* 1. 将输入的日期字符串转换为一个日期对象,并赋值给变量date。
* 2. 创建一个表示当前时间的日期对象,并赋值给变量now。
* 3. 计算当前时间与输入日期之间的时间差,并赋值给变量diff。
* 4. 如果时间差小于60秒,则计算出秒数并返回一个表示秒数的字符串。
* 5. 如果时间差小于60分钟,则计算出分钟数并返回一个表示分钟数的字符串。
* 6. 如果时间差小于24小时,则计算出小时数并返回一个表示小时数的字符串。
* 7. 如果以上条件都不满足,则返回一个表示日期的字符串,格式为"年-月-日"。
*/
export function dateToRelative(dateStr) {
const date = new Date(dateStr);
const now = new Date();
const diff = now - date;
if (diff < 1000 * 60) {
const seconds = Math.floor(diff / 1000);
return `${seconds}秒前`;
}
if (diff < 1000 * 60 * 60) {
const minutes = Math.floor(diff / (1000 * 60));
return `${minutes}分钟前`;
}
if (diff < 1000 * 60 * 60 * 24) {
const hours = Math.floor(diff / (1000 * 60 * 60));
return `${hours}小时前`;
}
return `${date.getFullYear()}-${("0" + (date.getMonth() + 1)).slice(
-2
)}-${("0" + (date.getDate() + 1)).slice(-2)}`;
}