花几天时间和小伙伴做了个仿知乎官网的项目,下面是我整理的项目搭建流程及部署和总结,如有不足之处欢迎大家批评指正!
一、目录结构
本项目使用vue-cli4脚手架创建,目录结构也比之前的2版本要简洁许多,下面是本项目的目录结构。
1.public
文件夹下的data
和found
放的是json
数据和图片资源,本来想直接调用知乎的数据接口,奈何没有权限,于是只好将json
数据保存在本地了~
2.assets
放的也是图片资源
3.components
放的是一些组件,Nav.vue
是页面的头部导航栏
index
里面放的是‘首页’的子组件,answer
里面的是‘等你来答’页面的子组件,因为‘发现’页面比较简单,只有一个组件,所以这里没有创建这个页面的子组件
4.router
路由配置,就不用介绍了~store
没用到也不用说了~
5.style
里边儿放的是样式文件,本项目使用了sass
预处理器,其中common.scss
写的是全局和公共样式,nav.scss
写的是头部导航栏的样式,因为有点多就把它单独拿出来写了,其他的就是各个组件的样式。
6.views
里面的就是三个大页面的父组件了~
二、页面结构及路由
1.首页
整体布局如下图所示
本项目使用了许多element-ui
的组件,比如导航、输入框、按钮、图标,对我们的开发提供了许多便利,但是也遇到了一些问题。
2.路由表
因为本项目做的页面比较少,路由表也较为简单,主要用的是懒加载,下面为部分配置:
三、过渡动画
本项目的过渡动画主要分为两大块,一个是刚进入项目时的动画,另一个是每个子组件的进入和离开动画。
1.页面初始载入动画
这里的动画是写在index.html
中的,因为项目打包部署后都是从这个文件访问页面的
样式就不展示了,如果想要加载动画可以在网上找找~重点在后面,这个动画应该在页面加载后移除,所以我们要在App.vue
中写一个钩子函数来移除它:
mounted () {
let apploading = document.getElementById('AppLoading');
if (apploading != null) {
document.body.removeChild(apploading);
}
}
2.组件的过渡
这里用到的是vue
提供的transition-group
内置过渡动画,因为子组件较多,所以我们用@mixin
在common.scss
中定义了一个公共的动画样式,并定义一个初始值,这样就可以传入不同的过渡从而实现不同的过渡效果
@mixin animate($translate: translateY(20px)) {
.v-enter-active {
transition: all .3s ease;
}
.v-leave-active {
transition: all .5s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.v-enter, .v-leave-to {
transform: $translate;
opacity: 0;
}
}
接着在组件里写一个transitoin-group
标签,这里要注意,这个标签里面只能有一个根结点,而且要给它绑定一个唯一的key
,否则会报错!
最后引入样式文件和动画:
<style lang="scss" scoped>
@import "../../style/common";
@import "../../style/index/index-main";
#body {
padding-bottom: 50px;
}
@include animate();
</style>
四、遇到的问题及占坑
1.element-ui
的navmenu导航路由
element-ui
的navmenu导航菜单是默认没有路由功能的,需要我们自己手动配置
<el-menu :default-active="this.$route.path" router class="el-menu-demo" mode="horizontal">
<el-menu-item index="/index">首页</el-menu-item>
<el-menu-item index="/found">发现</el-menu-item>
<el-menu-item index="/answer">等你来答</el-menu-item>
</el-menu>
2.一级路由不高亮
进行如上配置并在路由表配置一下就可以实现三个大页面的跳转了,但是到后来写二级路由的时候就出问题了,进入二级路由后,一级路由没有高亮了
这时候加上如下代码即可解决:
<el-menu :default-active="'/' + this.$route.path.split('/')[1]" router class="el-menu-demo" mode="horizontal">
大家应该都看得出来有什么区别吧!
3.json
数据与预期不一致
有时候我们用axios
获取json
的数据与预期数据有一些出入,比如这是获取的一个文章链接:“https://api.zhihu.com/questions/421796329”,而正确的文章链接应该是:“https://www.zhihu.com/question/421796329”,这时候就需要写一个filter
来加工一下了
<a :href="item.target.url | filter('question')">...</a>
filters: {
filter (val, str) {
let pattern = 'questions';
let res = val.replace(new RegExp(pattern), str);
return res.replace('api', 'www')
}
}
4.有些数据里没有图片
一条数据里可能没有图片地址,比如这样的
所以这时候要加点儿料了:
<img :src="item.children[0].thumbnail" onerror="this.style.display='none'">
当加载图片资源失败时就让img
标签隐藏,同时不能把放置文字的容器的宽度写死,应该给一个flex: 1 1
,当它右边没有内容时就会自然展开
5.右侧组件的固定
大家应该都发现了,当你滚动到一定位置的时候,右侧的组件会固定在一个位置
这个实现起来也简单,直接看代码:
思路就是绑定一个固定位置的class
,通过改变布尔值来控制是否固定,布尔值如何改变呢?在钩子函数里添加一个监听滚动事件,当页面偏移量大于某个值的时候为真,否则为假。这里要注意离开本页面的时候要移除这个监听事件!否则它会一直在后台监听滚动而引起不必要的内存消耗从而影响页面性能!
6.‘发现’页面的延迟动画
这个页面其实写了两个过渡动画,刚进入这个页面的时候显示的是第一个动画,当你滚动到‘专栏’的时候第二个动画才会触发,这个实现原理和上述组件的固定异曲同工,就是滚动到一定位置后再加载json
数据,看看代码就能明白了:
methods: {
load () {
this.$axios({
methods: 'get',
url: 'data/found.json'
})
.then(res => {
this.lists = res.data.lists
})
.catch(err => {
console.log(err);
})
},
handleScroll () {
if (window.pageYOffset > 450) this.load()
}
},
mounted () {
window.addEventListener('scroll', this.handleScroll)
},
destroyed () {
window.removeEventListener('scroll', this.handleScroll)
}
7.打包和部署
vue-cli4版本是没有build
文件夹的,如果我们需要额外的配置,需要在项目的根目录新建一个vue.config.js
文件,敲如下代码:
module.exports = {
publicPath: './'
}
然后再运行npm run build
进行打包,打包完成后就可以得到如下文件了
最后把里面的文件放到配置好nginx
的服务器里就可以了!
五、总结
总的来说,本次项目开发的还挺顺利,但我深知还存在许多不足之处,因为是第一次在项目里使用sass
预处理器,所以很多地方写的还很生硬,跟css
没差,写项目之前还是想的太少了,导致后来还是写了挺多重复的样式T_T,路漫漫其修远兮,还要加油!