哈哈好久不见,我们一起来欣赏代码呀
老规矩,放一下博主大大的github地址:https://github.com/daoket/vue.news
接下来我们来看看效果呀
接下来我们来一起看看代码呀
其实看了动图,我有几个想知道的实现的点,1.点击加载更多,2.中间部分的切换,如果有很多的UI,也可以实现很美好的效果呢3.然后就是侧边栏的
接下来我们一起看代码呀
我们在main.js中可以看到,项目是有使用懒加载的
//main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import './style/public.css'
import axios from 'axios' // 处理http请求
import store from './store' // 状态管理
import VueLazyload from 'vue-lazyload' // 懒加载
/**
* @desc 懒加载配置
* @author wtniu
*/
Vue.use(VueLazyload, {
preLoad: 1.3,
error: './assets/error.jpg',
loading: './assets/loading.gif',
attempt: 1
})
Vue.prototype.$axios = axios
// 去掉开发环境打印信息
Vue.config.productionTip = false
Vue.config.devtools = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
然后我们看看app.vue吧
app.vue中是比较有意思的,引用了四个组件,头部,底部中间部分以及侧边的
//app.vue
<template>
<div id="app">
<app-menu></app-menu>
<div class="page">
<app-head></app-head>
<app-nav></app-nav>
<!--keep-alive 切换路不会触发mounted-->
<keep-alive><router-view></router-view></keep-alive>
<app-foot></app-foot>
</div>
</div>
</template>
<script>
import AppHead from './components/public/Head'
import AppMenu from './components/public/Menu'
import AppNav from './components/public/Nav'
import AppFoot from './components/public/Foot'
export default {
name: 'app',
components: {
'app-head': AppHead,
'app-menu': AppMenu,
'app-nav': AppNav,
'app-foot': AppFoot
}
}
</script>
<style>
#app{
overflow: hidden;
}
.page{
position: relative;
z-index: 99;
transition: all 0.5s;
}
.toggle{
transform: translateX(-120px);
}
</style>
我们先看头部和底部的,感觉很好写的
先看footer啦
//foot.vue
<template>
<footer class="foot">
<img src="../../assets/head/logo.png"/>
<div class="email">
<p>联系我:wt_niu@163.com</p>
<a href="https://github.com/daoket/vue.news"><p>Fork me on GitHub</p></a>
</div>
</footer>
</template>
<style lang="scss">
.foot{
height: 100px;
background-color: #262627;
display: flex;
color: #fff;
justify-content: space-around;
align-items: center;
img{
height: 20px;
margin-left: 10%;
padding-right: 5%;
border-right: 1px solid #666;
}
.email{
font-size: 13px;
p{
margin: 10px 0;
}
}
}
</style>
其实head部分我认为内容很少的,怎么感觉代码超出了自己的认知
作者大大写的时候,把右边menu,点击关闭和展示,是写在了store里面,然后还有回到首页的功能,不过我好像没有看到搜索的功能
后面看代码的时候发现是作者大大自己注释了
//head.vue
<template>
<header class="head">
<a href="javascript: void(0)"><img class="vNews" @click="goHome" src="../../assets/head/logo.png"/></a>
<svg class="icon searchBtn" @click='openSearch' aria-hidden="true">
<use xlink:href="#icon-sousuo"></use>
</svg>
<div class="searchPage">
<div class="header">
<div class="search">
<input v-model='searchContent' type="text" />
<svg class="icon" @click='searchNewsBtn' aria-hidden="true">
<use xlink:href="#icon-sousuo"></use>
</svg>
</div>
<svg class="icon close" @click='closeSearch' aria-hidden="true">
<use xlink:href="#icon-hao"></use>
</svg>
</div>
<div class="content">
<p class="today">今天</p>
<ul class="news">
<li ref='newsItem' v-for='(news, index) in searchNews' :key='index'>
<a :href="'#' + news.id" @click='goNews'>
<p v-if='+index < 3'><i class="isTop3"> {{index + 1}} </i><span ref='title' class="title"> {{news.title}}</span></p>
<p v-else><i> {{index + 1}} </i><span ref='title' class="title"> {{news.title}}</span></p>
</a>
</li>
</ul>
</div>
</div>
<div class="aside" @click='toggleMenu'>
<div v-for='i in 3' :key='i' class="line"></div>
</div>
</header>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
name: 'apphead', // Do not use built-in or reserved HTML elements as component id
data () {
return {
imgs: [],
searchContent: ''
}
},
computed: {
...mapState({
searchNews: state => state.SelectStore.searchNews
})
},
watch: {
searchContent (curVal) {
if (curVal === '') {
this.$refs.newsItem.map((item) => {
item.style.display = 'block'
item.className = ''
})
}
if (curVal !== '') {
this.$refs.title.map((item) => {
if (item.innerText.match(curVal)) {
item.parentNode.parentNode.parentNode.className = 'hightColor'
} else {
item.parentNode.parentNode.parentNode.style.display = 'none'
}
})
}
}
},
methods: {
setClass (classname) {
return classname
},
setSrc (src) {
return src
},
searchNewsBtn () {
console.log('..searchNewsBtn..')
alert('搜索完成')
},
goNews () {
console.log('goNews..')
this.closeSearch()
this.clearSearchContent()
},
goHome () {
console.log('goHome..goHome')
this.$router.push('/select')
},
clearSearchContent () {
this.searchContent = ''
},
...mapMutations([
'toggleMenu', 'openSearch', 'closeSearch'
])
}
}
</script>
<style lang="scss">
.head{
height: 60px;
background: #262627;
position: relative;
img{
height: 50px;
position: absolute;
top: 5px;
right: 20%;
cursor: pointer;
}
.vNews{
height: 20px;
top: 20px;
left: 10px;
}
.baidu{
right: 30%;
}
.searchBtn{
cursor: pointer;
color: #FFFFFF;
position: absolute;
top: 18px;
right: 15%;
}
.aside{
height: 60px;
60px;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
padding-top: 1px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
.line{
height: 1px;
25px;
background: #fff;
transition: all 0.5s;
}
.line:nth-of-type(2){
margin: 6px 0;
}
}
.closeMenu{
.line:first-child{
transform: rotate(45deg);
}
.line:nth-child(2){
display: none;
}
.line:last-child{
transform: rotate(-45deg);
}
}
.searchPage{
display: none;//隐藏了搜索的功能
position: fixed;
height: 100%;
100%;
overflow: scroll;
background: #fff;
z-index: 999;
.header{
height: 60px;
display: flex;
justify-content: space-around;
align-items: center;
padding: 0 2%;
background: #262627;
.search{
height: 40px;
85%;
border: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
input{
height: 40px;
82%;
color: #FFFFFF;
text-indent: 10px;
background-color: #262627;
outline: none;
}
.icon{
color: #FFFFFF;
margin-right: 5%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
}
.close{
height: 30px;
30px;
color: #FFFFFF;
}
}
}
.content{
overflow: hidden;
background-color: #FFFFFF;
.today{
height: 25px;
background: #E3E4EE;
line-height: 25px;
text-indent: 15px;
font-size: 14px;
}
.news li{
font-size: 16px;
margin: 15px;
p{
100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
i{
font-size: 16px;
font-style: normal;
margin-right: 10px;
}
i.isTop3{
color: red;
}
span{
90%;
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
.hightColor{
color: #FFFFFF;
background-color: #EEEEEE;
}
}
</style>
/**
* @desc 显示隐藏右侧菜单
*/
export default {
mutations: {
toggleMenu () {
var page = document.querySelector('#app .page')
var aside = document.querySelector('.head .aside')
var pageClass = page.className
var asideClass = aside.className
if (pageClass === 'page') {
page.className = 'page toggle'
} else {
page.className = 'page'
}
if (asideClass === 'aside') {
aside.className = 'aside closeMenu'
} else {
aside.className = 'aside'
}
},
openSearch () {
alert('11')
var searchPage = document.querySelector('.head .searchPage')
searchPage.style.display = 'block'
},
closeSearch () {
console.log('2222')
var searchPage = document.querySelector('.head .searchPage')
searchPage.style.display = 'none'
}
}
}
接下来我们来看app-menu组件
//menu.vue
<template>
<section class="menus">
<p class="user" title="">{{userName}}</p>
<ul class="aside">
<li v-for='(m, index) in menus' :key='index'><a href="">{{m.text}}</a></li>
</ul>
</section>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState({
userName: state => state.MenuStore.userName,
menus: state => state.MenuStore.menus
})
}
}
</script>
<style lang="scss">
.menus{
position: fixed;
top: 0;
right: 0;
color: #fff;
120px;
height: 100%;
background: #3C3C3D;
z-index: 9;
.user{
height: 60px;
line-height: 60px;
background: #000;
text-align: center;
60%;
padding: 0 20%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.aside li{
height: 50px;
60%;
padding: 0 20%;
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
a{
height: 100%;
color: #FFFFFF;
line-height: 50px;
display: inline-block;
}
}
.aside li:hover{
background-color: #3E90E3;
}
}
</style>
这个menus值也是在store中存储的
//menuStore.js
/**
* @desc 右侧菜单数据
*/
export default {
state: {
userName: '京州市委书记李达康',
menus: [{
text: '巨头'
}, {
text: '人物'
}, {
text: '电商'
}, {
text: '创投'
}, {
text: '智能硬件'
}, {
text: '互联网+'
}, {
text: 'P2P'
}, {
text: '前沿技术'
}, {
text: '游戏'
}]
}
}
接下来我们看nav.vue中
//nav.vue
<template>
<section class="nav">
<!--v-for遍历路由-->
<div class="nav" v-for='(m, index) in menus' :key='index'>
<router-link :to='setPaht(m.path)'><span>{{m.text}}</span></router-link>
</div>
</section>
</template>
<script>
export default {
data () {
return {
// 路由参数
menus: [{
text: '精选',
path: '/select'
}, {
text: '话题',
path: '/point'
}, {
text: '作者',
path: '/author'
}]
}
},
methods: {
setPaht (path) {
return path
}
}
}
</script>
<style lang="scss">
.nav{
100%;
height: 50px;
display: flex;
justify-content: space-around;
align-items: center;
background: #fff;
.nav{
33%;
height: 100%;
a{
height: 100%;
100%;
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
color: #666;
font-size: 18px;
text-align: center;
span:first-child{
height: 30px;
100%;
line-height: 30px;
}
}
}
div:nth-child(2) > a > span{
border-left: 1px solid #eee;
border-right: 1px solid #eee;
}
.active{
border-bottom: 1px solid red;
box-sizing: border-box;
}
}
</style>
接下来我们看select.vue
<template>
<div class="select">
<div class="banner">
<swiper :options="swiperOption" ref="mySwiper">
<!-- 这部分放你要渲染的那些内容 -->
<swiper-slide v-for='img in banners' :key="img.channelId">
<img :src="setBannerSrc(img)"/>
</swiper-slide>
<!-- 这是轮播的小圆点 -->
<div v-show='loadBtn' class="swiper-pagination" slot="pagination"></div>
</swiper>
</div>
<!--加载动画-->
<div class="spinner" v-show='loadAnimation'></div>
<transition name='fade' mode='out-in'>
<svg v-show='rocket' class="icon goTop" @click='goPageTop' aria-hidden="true">
<use xlink:href="#icon-0028"></use>
</svg>
</transition>
<section class="news">
<div v-if='requestStatus'>
<div v-for='(news, index) in newsDate' :key='index' :id="news.id">
<a href="javascript: void(0)" class="new" :key='news.channelId'>
<img v-lazy='news.imageurls[0].url' :src="setNewSrc(news.imageurls[0].url)"/>
<div class="intro">
<h4>{{news.title}}</h4>
<p><span>{{news.source}}</span> | <span>{{news.pubDate}}</span></p>
</div>
</a>
</div>
<button class="loadMore" @click='loadMoreBtn' v-show='loadBtn'>点击加载更多</button>
</div>
<div class="fail" v-else>/(ㄒoㄒ)/~~, 请求到数据失败!</div>
</section>
</div>
</template>
<script>
// 导入轮播图组件
import { swiper, swiperSlide } from 'vue-awesome-swiper'
// 导入vuex
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
data () {
return {
rocket: false,
requestStatus: true,
swiperOption: {
pagination: '.swiper-pagination',
slidesPerView: 'auto',
centeredSlides: true,
paginationClickable: true,
spaceBetween: 30,
onSlideChangeEnd: swiper => {
// 这个位置放swiper的回调方法
this.page = swiper.realIndex + 1
this.index = swiper.realIndex
}
}
}
},
computed: {
/**
* @desc 从store中引入需要的数据
*/
...mapState({
page: state => state.SelectStore.page,
newsUrl: state => state.SelectStore.newsUrl,
banners: state => state.SelectStore.banners,
newsDate: state => state.SelectStore.newsDate,
loadBtn: state => state.SelectStore.loadBtn,
pathName: state => state.SelectStore.pathName,
loadAnimation: state => state.SelectStore.loadAnimation
})
},
created: function () {
this.askNews(this.newsUrl + this.page) // 第一次加载请求数据
let _this = this
/**
* @desc 判断是否显示回到顶部的火箭图标
*/
window.onscroll = function () {
let leaveTop = document.body.scrollTop
if (leaveTop > 600) {
_this.rocket = true
} else {
_this.rocket = false
}
}
console.log(`%c ${this.$store.state.slogan}`,"font-size: 22px;color:#00BBEE", "Copyright © 2019");
},
methods: {
...mapActions([
'askNews', 'setSrc'
]),
...mapMutations([
'loadMore'
]),
/**
* @desc 设置轮播图地址
*/
setBannerSrc (src) {
return src
},
/**
* @desc 设置新闻图片地址
*/
setNewSrc (url) {
return url
},
/**
* @desc 加载更多
*/
loadMoreBtn () {
this.loadMore()
this.askNews(this.newsUrl + this.page)
},
/**
* @desc 回到顶部
*/
goPageTop () {
document.body.scrollTop = 0
}
},
components: {
swiper,
swiperSlide
}
}
</script>
<style lang="scss">
.select{
background: #fff;
.swiper-wrapper{
height: 200px;
.swiper-slide img{
100%;
height: 200px;
}
}
.news{
min-height: 500px;
padding: 0 10px;
.new{
height: 100px;
color: #262627;
border-bottom: 1px solid #eee;
display: flex;
justify-content: flex-start;
align-items: center;
100%;
img{
height: 80px;
100px;
}
.intro{
80%;
height: 80px;
display: flex;
padding-left: 10px;
flex-direction: column;
justify-content: space-between;
h4{
font-size: 20px;
line-height: 1.2;
font-weight: bold;
overflow: hidden;
display: -webkit-box;
word-break: break-all;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
}
p{
font-size: 13px;
color: #666;
}
}
}
.loadMore{
height: 50px;
100%;
color: #545454;
background: #eee;
text-align: center;
line-height: 50px;
font-size: 13px;
border: none;
border-radius: 0;
outline: none;
margin-bottom: 10px;
}
.fail{
display: flex;
min-height: 300px;
align-items: center;
justify-content: center;
}
}
}
/*加载动画*/
.spinner {
position: fixed;
left: 40%;
bottom: 10%;
80px;
height: 80px;
margin: 50px auto;
background-color: #69C61D;
border-radius: 100%;
-webkit-animation: scaleout 1.0s infinite ease-in-out;
animation: scaleout 1.0s infinite ease-in-out;
}
@-webkit-keyframes scaleout {
0% { -webkit-transform: scale(0.0) }
100% {
-webkit-transform: scale(1.0);
opacity: 0;
}
}
@keyframes scaleout {
0% {
transform: scale(0.0);
-webkit-transform: scale(0.0);
} 100% {
transform: scale(1.0);
-webkit-transform: scale(1.0);
opacity: 0;
}
}
.goTop{
color: #50BFFF;
position: fixed;
bottom: 40px;
right: 20px;
z-index: 9999;
cursor: pointer;
60px;
height: 60px;
transition: all 1s ease;
transform: scale(0.6);
}
.goTop:active{
color: #C40000;
transform: scale(1);
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.8s
}
.fade-enter, .fade-leave-active {
opacity: 0
}
.tip{
100%;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
a{
color: #19C8A9;
}
span{
margin-bottom: 10px;
}
}
</style>
加载更多的代码也有在store中定义
//selectStore.js
import axios from 'axios'
import $ from 'webpack-zepto'
export default {
state: {
page: 1,
data: [],
newsDate: [],
banners: [],
searchNews: [],
loadBtn: false,
loadAnimation: true,
newsUrl: 'https://route.showapi.com/109-35?showapi_appid=34477&showapi_sign=cfa5957a730f43d38886bd16469b2a86&channelId=5572a108b3cdc86cf39001cd&needContent=0&needHtml=1&page='
},
mutations: {
/**
* @desc 加载新闻
*/
loadNews (state) {
let data = state.data
if (data.length > 2) { // 判断数据是否存在
for (var i = 0; i < data.length; i++) {
if (data[i].imageurls[0]) {
state.newsDate.push(data[i])
}
}
for (let i = 0; i < 4; i++) {
if (state.banners.length < 4) {
state.banners.push(state.newsDate[i].imageurls[0].url)
}
}
} else {
state.loadAnimation = false
console.log('没有更多数据了')
return false
}
// 数据请求成功显示加载更多按钮
state.loadBtn = true
state.loadAnimation = false
},
/**
* @desc 点击加载更多
*/
loadMore (state) {
state.page++
state.loadAnimation = true
},
updatePathName (state, newPathName) {
state.pathName = newPathName
}
},
actions: {
/**
* @desc axios异步请求函数 类似jquery的ajax方法
*/
askNews ({commit, state}, url) {
axios({
method: 'get',
url: url
})
.then((res) => {
if (res.data.showapi_res_code !== -2) {
let data = res.data.showapi_res_body.pagebean.contentlist
state.data = data
for (let i in data) {
state.searchNews.push({title: data[i].title, id: data[i].id})
}
} else {
var tips = `<p class="tip">
<span>接口请求已达上限 /(ㄒoㄒ)/~~!!!</span>
<span>选择和AI聊天,缓解失望的心情吧:</span>
<a href="http://lx.openspeech.cn/auth/project/ai_niu/index.html">快来和我聊天!</a>
</p>`
$(tips).appendTo('.news')
}
commit('loadNews')
})
}
}
}
接下来看话题页面
其实我很好奇,为什么把数据写在store中
//pointStore.js
/**
* @desc 话题页面数据
*/
export default {
state: {
points: [{
times: '609期',
title: '提高个税起征点真能减负嘛?',
msg: '3月7日,财政部部长肖捷在发布会上表示,个人所得税免征额将根据消费水平综合测算,...'
}, {
times: '609期',
title: '提高个税起征点真能减负嘛?',
msg: '3月7日,财政部部长肖捷在发布会上表示,个人所得税免征额将根据消费水平综合测算,...'
}, {
times: '609期',
title: '提高个税起征点真能减负嘛?',
msg: '3月7日,财政部部长肖捷在发布会上表示,个人所得税免征额将根据消费水平综合测算,...'
}]
}
}
<template>
<section class="point">
<div class='question'>
<div class="mask">
<h2>热点城市房价会否持续疯涨?</h2>
<p>610期</p>
<div class="result">
<p><span>正方</span><span>反方</span></p>
<progress value="75" max="100"></progress>
<p><span>75%</span><span>25%</span></p>
</div>
<a class="join" href="javascript: void(0)">进入专题></a>
</div>
</div>
<div class="prev">
<div v-for='(p, index) in points' :key='index' class="list">
<div class="mask">
<span class="times">{{p.times}}</span>
<h2>{{p.title}}</h2>
<p>{{p.msg}}</p>
<a class="join" href="javascript: void(0)"> > </a>
</div>
</div>
</div>
</section>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'point',
computed: {
...mapState({
points: state => state.PointStore.points
})
}
}
</script>
<style lang="scss">
.point{
color: #fff;
background: #fff;
.question{
height: 180px;
background: url(../assets/point/pointBg.jpg);
background-size: 100% 100%;
.mask{
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
height: 100%;
100%;
position: relative;
background: rgba(0,0,0,0.6);
h2{
font-size: 20px;
font-weight: bold;
}
p{
font-size: 16px;
margin: 10px 0;
}
.result{
height: 100px;
80%;
p{
display: flex;
justify-content: space-between;
}
progress {
100%;
background-color:#005588;
color: #E94C3D; /*IE10*/
}
progress::-moz-progress-bar { background: #E94C3D; }
progress::-webkit-progress-bar { background: #005588; }
progress::-webkit-progress-value { background: #E94C3D; }
}
.join{
color: #E94C3D;
position: absolute;
bottom: 10px;
right: 10px;
}
}
}
.prev{
padding: 10px;
.list{
height: 150px;
100%;
margin-bottom: 10px;
overflow: hidden;
background: url(../assets/point/pointBg.jpg) no-repeat;
background-size: 100%;
.mask{
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
height: 100%;
100%;
background: rgba(0,0,0,0.6);
position: relative;
h2{
font-size: 20px;
font-weight: bold;
100%;
text-align: center;
padding: 0 20px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
p{
color: #eee;
margin: 10px 20px;
line-height: 1.3;
font-size: 13px;
overflow: hidden;
display: -webkit-box;
word-break: break-all;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
}
.times{
position: absolute;
left: 0;
top: 0;
color: #eee;
display: inline-block;
padding: 2px;
font-size: 13px;
}
.join{
position: absolute;
right: 5px;
bottom: 0;
color: #eee;
color: #E94C3D;
display: inline-block;
padding: 10px;
font-size: 13px;
}
}
}
}
}
</style>
接下来是author页面
<template>
<section class="author">
<button class="goHome" @click='goHome'>Home</button>
<!--<a v-link="select">select</a>-->
<div class="banner">
<div v-for='(a, index) in author' :key='index' class="item">
<div class="msg">
<img :src="setAutherSrc(a.src)"/>
<p class="name">{{a.name}}</p>
<p class="slogan">{{a.slogan}}</p>
</div>
<span class="focus" v-if='a.status' @click='a.status = !a.status'>关注</span>
<span class="focus focused" @click='a.status = !a.status' v-else>已关注</span>
</div>
</div>
<section class="more">
<div v-for='(o, index) in other' :key='index' class="other">
<div class="authorMsg">
<img :src="setOtherSrc(o.src)"/>
<div class="intro">
<p class="name">{{o.name}}</p>
<p class="slogan">{{o.slogan}}</p>
</div>
</div>
<div>
<span class="focus" v-if='o.status' @click='o.status = !o.status' >关注</span>
<span class="focus focused" @click='o.status = !o.status' v-else>已关注</span>
</div>
</div>
</section>
</section>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'author',
computed: {
...mapState({
author: state => state.AuthorStore.author,
other: state => state.AuthorStore.other,
pathName: state => state.SelectStore.pathName
})
},
watch: {
'$route': 'fetchData'
},
methods: {
setAutherSrc (src) {
return src
},
setOtherSrc (src) {
return src
},
fetchData () {
location.hash = 'select'
console.log(this.$route)
},
goHome () {
if (history.length) {
this.$router.go(parseFloat(-this.$store.state.historyLength) + 1)
}
}
},
beforeRouteEnter (to, from, next) {
next()
},
beforeRouteUpdate (to, from, next) {
console.log(9)
next()
},
beforeRouteLeave (to, from, next) {
next()
}
}
</script>
<style lang="scss">
.author{
background: #fff;
border-right: 1px solid #666;
.banner{
background: url(../assets/author/author_banner_bg.jpg);
.item{
height: 210px;
45%;
margin: 2%;
color: #fff;
opacity: 0.9;
display: inline-block;
text-align: center;
background: #2E2E2F;
.msg{
display: flex;
flex-direction: column;
background: #262627;
padding: 10px 0;
justify-content: space-around;
align-items: center;
img{
height: 100px;
100px;
border-radius: 50%;
}
.name{
margin: 10px 0;
}
.slogan{
color: #666;
80%;
font-size: 13px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.focus{
80px;
font-size: 13px;
display: inline-block;
padding: 4px 0;
background: #E94C3D;
border-radius: 10px;
cursor: pointer;
margin: 10px 0;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.focused{
background: #262627;
}
}
}
.more{
padding: 10px;
.other{
height: 100px;
background: #eee;
display: flex;
margin-bottom: 10px;
justify-content: space-between;
padding: 0 10px;
align-items: center;
.authorMsg{
display: flex;
justify-content: space-between;
align-items: center;
img{
height: 80px;
80px;
border-radius: 50%;
}
.intro{
height: 40px;
margin: 0 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
.slogan{
font-size: 13px;
color: #666;
}
}
}
.focus{
display: inline-block;
80px;
color: #fff;
cursor: pointer;
font-size: 13px;
text-align: center;
padding: 5px 0;
background: #D5483A;
border-radius: 15px;
margin-left: 10px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.focused{
background: #262627;
}
}
}
.goHome{
position: fixed;
right: 15px;
bottom: 30px;
50px;
height: 50px;
border-radius: 50%;
border: none;
outline: none;
color: #FFFFFF;
background: rgba(0,0,0,0.5);
}
}
</style>
AuthorStore.js中进入到对应的页面也是在state中
//authodStore.js
/**
* @desc 作者页面数据
*/
export default {
state: {
author: [{
src: require('../assets/author/author.jpg'),
name: '变革家',
slogan: '帮股权投资者把好第一关!',
status: true
}, {
src: require('../assets/author/author.jpg'),
name: '懂懂笔记',
slogan: '20年国内财经媒体从业记录者!',
status: true
}, {
src: require('../assets/author/author.jpg'),
name: '变革家',
slogan: '帮股权投资者把好第一关!',
status: true
}, {
src: require('../assets/author/author.jpg'),
name: '娱乐硬糖',
slogan: '有温度的泛娱乐产业自媒体。!',
status: true
}],
other: [{
src: require('../assets/author/author.jpg'),
name: '邝新华',
slogan: '新周刊主笔',
status: true
}, {
src: require('../assets/author/author.jpg'),
name: '40秒',
slogan: '认识最疯狂的天才',
status: true
}, {
src: require('../assets/author/author.jpg'),
name: '艾问iAsk',
slogan: '科技商业价值发现者',
status: true
}]
}
}
最后就是router.js
import Vue from 'vue'
import Router from 'vue-router'
import store from '../store'
import Select from '../components/Select'
import Point from '../components/Point'
import Author from '../components/Author'
Vue.use(Router)
const router = new Router({
linkActiveClass: 'active',
hashbang: true, // 将路径格式化为#!开头
history: true, // 启用HTML5 history模式,可以使用pushState和replaceState来管理记录
/**
* @desc 路由配置
*/
routes: [
{
path: '/select',
component: Select
}, {
path: '/point',
component: Point
}, {
path: '/author',
component: Author,
meta: { requiresAuth: true }
}, {
path: '/*',
component: Select
}
]
})
/**
* @desc 全局监听路由变化
*/
router.beforeEach((to, from, next) => {
store.dispatch('updateHistoryLength') // 变化时更新路由切换长度
next()
})
export default router
其实不太理解作者写的这个路由的切换次数
···js
/**
- @desc 导入需要的store
- @author wtniu
*/
import Vue from 'vue'
import Vuex from 'vuex'
import SelectStore from './SelectStore'
import PointStore from './PointStore'
import AuthorStore from './AuthorStore'
import MenuStore from './MenuStore'
import HeadStore from './HeadStore'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
slogan: '叩首为梦 码梦为生!',
historyLength: 0
},
mutations: {
/*
* @desc 记录路由切换次数
* @arg {object} state 状态
*/
updateHistoryLength (state) {
state.historyLength++
}
},
actions: {
updateHistoryLength ({commit}) {
commit('updateHistoryLength')
}
},
modules: {
SelectStore,
PointStore,
AuthorStore,
MenuStore,
HeadStore
}
})
作者大大的这样项目很值得推荐的,将数据放在store的state中这种方法很很新颖,很喜欢,推荐