構建第一個Vue專案
之前的文章已經提到了,如何配置Vue的開發環境了,現在開始做一個簡單的專案,主要就是介紹怎麼使用元件、路由以及通訊等,大家就不要吐槽UI和樣式的問題。
這是我的src目錄,component是放公用元件的,page是頁面,static是放靜態資原始檔
首先先來看看main.js
我們需要在這裡引入我們需要用到的元件和庫
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' /* 這裡是引入vue檔案 */ import App from './App' /* 這裡是引入同目錄下的App.vue模組 */ import router from './router' /* 這裡是引入vue的路由 */ import VueResource from 'vue-resource' Vue.use(VueResource) /* eslint-disable no-new */ new Vue({ el: '#app', /* 定義作用範圍就是index.html裡的id為app的範圍內 */ router, /* 引入路由 */ components: { App }, /* 註冊引入的元件App.vue */ template: '<App/>' /* 給Vue例項初始一個App元件作為template 相當於預設元件 */ })
我們先來做頭部的導航欄,建立一個headerNav.vue
<template lang="html"> <div class="header"> <span class="back-btn" @click="goBack()">←</span> <h6 class="header-name" v-text="hName"></h6> </div> </template> <script> export default { return { hName:'首頁', }, methods:{ goBack(){ history.back(-1); } }, } </script> <style lang="css" scoped>/* scoped的意思是這裡的樣式只對當前頁面有效不會影響其他頁面,還有可以設定lang="scss"就是支援css預編譯,也就是支援sass或者less */ .header{ width: 100%; height: 2rem; padding: 0 2.6rem; position: fixed; left: 0; top: 0; background-color: #42b983; color: #ffffff; } .header-name { width: 80%; margin: 0 10%; text-align: center; line-height: 2rem; font-size: .8rem; } .back-btn{ display: inline-block; position: absolute; top: 0; left: 0; width: 2.6rem; height: 2rem; line-height: 2rem; font-size: 1.1rem; text-align: center; } </style>
有頭就要有尾,footerNav.vue
<template lang="html"> <div class="footer"> <ul class="footer-con b2 ui-transition"> <li class="g1">1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div> </template> <script> export default { data(){ }, } </script> <style lang="css"> .footer { height: 2rem; width: 100%; position: fixed; bottom: 0; left: 0; background-color: #fff; } .footer::before{ content: ''; display: block; position: absolute;top: 0;left: 0; width: 100%;height: 1px; background: #e0e0e0; } .footer-con li { float: left; width: 25%; height: 2rem; line-height: 2rem; font-size: .8rem; text-align: center; -webkit-transition: ease 0.25s; -moz-transition: ease 0.25s; -ms-transition: ease 0.25s; -o-transition: ease 0.25s; transition: ease 0.25s; } .footer-con li:active { background-color: rgb(248, 248, 248); } .footer-con:after { content: ''; display: block; clear: both; width: 0; height: 0; } </style>
接下來就是App.vue
<template lang="html">
<div class="container">
<!-- 引入的header元件 -->
<headerNav></headerNav>
<div class="content">
<router-view></router-view> <!-- 這裡是展示來自路由頁面資料的 -->
</div>
<!-- 引入的footer元件 -->
<footerNav></footerNav>
</div>
</template>
<script>
/* 引用元件 */
import headerNav from "@/components/headerNav";
import footerNav from "@/components/footerNav";
export default {
data() {
/* 這裡是資料,注意資料一定要放data中然後用return返回 */
return {
};
},
components: {
headerNav,
footerNav,
},
mounted(){},
};
</script>
<style lang="css">
blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{margin:0;padding:0}html{overflow-y:scroll}body{font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,SimSun,sans-serif;font-size:14px;-webkit-font-smoothing:antialiased;background-color:#fff;position:relative}ul,ol{list-style:none}a{text-decoration:none;}em{font-style:normal}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;outline:0 none} a{color: inherit} .clear::after{visibility:hidden;display:block;font-size:0;content:" ";clear:both;height:0}.clear{*zoom:1} .ui-transition { -webkit-transition: ease 0.35s; -moz-transition: ease 0.35s; -ms-transition: ease 0.35s; -o-transition: ease 0.35s; transition: ease 0.35s; } .b1{color: #646262;}.b2{color: #555454;} .o1{color: #f16f47;} .r1{color: rgb(233, 10, 103)} .g1{color: #42b983} .bl{color: #2c3e50;} body{background-color: rgba(233, 233, 233, .5);} .container { width: 100%; padding: 2rem 0; position: relative; }
</style>
現在應該就能看到一個只有頭尾,中間空白的頁面
所以我們要開始豐富內容,movieList.vue
<template lang="html">
<ul class="cont-ul clear">
<li class="cont-li b1" v-for="item in movieList">
<div class="img-con">
<img class="movie-img" :src="item.images.large">
</div>
<div class="movie-msg clear">
<p class="movie-name">{{item.title}}</p>
<p class="movie-price r1">
<span>評分 </span>{{item.rating.average}}</p>
</div>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
movieList: [],
};
},
mounted() {
// 這個是vue的鉤子函式,當new Vue()例項建立完畢後執行的函式,關於vue的生命週期,可以去官網檢視詳情
// 這裡我用的是豆瓣的一個公共介面
this.$http
.jsonp("https://api.douban.com/v2/movie/top250?count=10")
.then(res => {
this.movieList = res.data.subjects;
res = null;
})
.catch(error => {
console.log("http error:" + error);
});
},
};
</script>
<style lang="css" scoped>
.cont-ul { padding: 0.5rem 0.5rem 0 0.5rem; } .cont-li { margin-bottom: 0.4rem; width: calc(50% - 0.2rem); float: left; overflow: hidden; border-radius: 4px; background: #ffffff; box-shadow: 1px 1px 4px rgba(131, 131, 131, 0.5); } .cont-li:nth-child(2n-1) { margin-right: 0.4rem; } .img-con { height: 12rem; overflow: hidden; } .movie-img { float: left; width: 100%; } .movie-msg { width: 100%; padding: 0.3rem 0.5rem; } .movie-name { line-height: 1.2rem; font-size: 0.8rem; } .movie-price { text-align: right; line-height: 1rem; font-size: 0.7rem; font-weight: 400; } .movie-price span { font-size: 0.5rem; }
</style>
好了,現在我們就把第一個頁面做出來了,很簡單對吧。接下來就是詳情頁了,但是在這之前我們還需要定義跳轉方式,詳細請看我另一篇文章→
下面就是修改後的movieList.vue,增加了goToInfo的跳轉方法
<template lang="html">
<ul class="cont-ul clear">
<li class="cont-li b1" v-for="item in movieList" @click="goToInfo(item)">
<div class="img-con">
<img class="movie-img" :src="item.images.large">
</div>
<div class="movie-msg clear">
<p class="movie-name">{{item.title}}</p>
<p class="movie-price r1">
<span>評分 </span>{{item.rating.average}}</p>
</div>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
movieList: [],
};
},
mounted() {
// 這個是vue的鉤子函式,當new Vue()例項建立完畢後執行的函式,關於vue的生命週期,可以去官網檢視詳情
// 這裡我用的是豆瓣的一個公共介面
this.$http
.jsonp("https://api.douban.com/v2/movie/top250?count=10")
.then(res => {
this.movieList = res.data.subjects;
console.log(res.data.subjects);
res = null;
})
.catch(error => {
console.log("http error" + error);
});
},
methods:{
goToInfo(info){
//這裡因為我想把整個物件傳給詳情頁,所以使用的是session
sessionStorage.setItem('movieInfo',JSON.stringify(info));
this.$router.push({
path:'/movieInfo', //路徑
name:'movieInfo', //配置路由時的name
});
}
}
};
</script>
其實正常來說,我們應該是在movieList.vue 通過路由query的方式把id傳給詳情頁,但是因為沒有介面的原因所以我用了session
然後就是詳情頁了,movieInfo.vue
<template lang="html">
<div class="info-con" v-if="info">
<img class="movie-img" :src="info.images.large">
<p class="movie-name">{{info.title}}<span>{{' ('+info.year+')'}}</span></p>
<p>
型別:
<span v-for="genre in info.genres">{{genre+' / '}}</span>
</p>
<p class="o1">評分:{{info.rating.average}}</p>
</div>
</template>
<script>
export default {
data() {
return {
info:'',
};
},
mounted() {
let info = sessionStorage.getItem('movieInfo')||0;
if(info){
this.info = JSON.parse(info);
}
}
};
</script>
<style lang="css" scoped>
.info-con { padding: 1rem; margin: 1rem; border-radius: 8px; background: #ffffff; box-shadow: 1px 1px 6px rgba(131, 131, 131, 0.5); overflow: hidden; } .info-con img{ width: 100%; } .info-con .movie-name { margin-top: .5rem; text-align: left; line-height: 2rem; font-size: .9rem; font-weight: 400; } .movie-name span{color: grey;font-size: .8rem;}
</style>
在執行之前,我們還需要在router資料夾下的index.js檔案裡配置好路由
import Vue from 'vue'
import Router from 'vue-router' /* 引用vue路由模組,並賦值給變數Router */
import movieList from '@/page/movieList.vue'
import movieInfo from '@/page/movieInfo.vue'
Vue.use(Router) /* 使用路由 */
export default new Router({
routes: [ /* 進行路由配置,規定“/”引入到元件 */
{
path: '/',//預設頁面
name: 'movieList',
component: movieList /* 註冊元件 */
},
{
path: '/movieList',
name: 'movieList',
component: movieList
},
{
path: '/movieInfo',
name: 'movieInfo',
component: movieInfo
}
]
})
現在在控制檯輸入 npm run dev 我們就可以看到整個效果了
但是我們希望頭尾的導航欄能根據我們的頁面顯示不同的資訊,這時候就需要用到通訊功能了,詳情→
首先我們在movieList.vue 的mounted裡給App.vue傳一個title和footer的index
mounted() {
this.$emit('setNav',['豆瓣評分Top250電影',1]);
// 這個是vue的鉤子函式,當new Vue()例項建立完畢後執行的函式
this.$http
.jsonp("https://api.douban.com/v2/movie/top250?count=10")
.then(res => {
this.movieList = res.data.subjects;
res = null;
})
.catch(error => {
console.log("http error" + error);
});
}
同樣的在movieInfo.vue 的mounted裡也給App.vue傳當前的電影名和footer的index
mounted() {
let info = sessionStorage.getItem('movieInfo')||0;
if(info){
this.info = JSON.parse(info);
}
this.$emit('setNav',[this.info.title,2]);
}
然後在App.vue裡通過setNav函式接受子元件的引數,並把這兩個引數傳遞給headerNav和footerNav
<template lang="html">
<div class="container">
<!-- 引入的header元件 -->
<headerNav :navTitle="navTitle"></headerNav>
<div class="content">
<router-view v-on:setNav="setNav"></router-view> <!-- 這裡是展示來自路由頁面資料的 -->
</div>
<!-- 引入的footer元件 -->
<footerNav :nowTab="nowTab"></footerNav>
</div>
</template>
<script>
/* 引用元件 */
import headerNav from "@/components/headerNav";
import footerNav from "@/components/footerNav";
export default {
data() {
/* 這裡是資料,注意資料一定要放data中然後用return返回 */
return {
navTitle:'',
nowTab:1,
};
},
components: {
headerNav,
footerNav,
},
mounted(){},
methods:{
setNav(seterArr){
this.navTitle = seterArr[0];
this.nowTab = seterArr[1];
}
}
};
</script>
然後headerNav和footerNav只需要通過props接收就行了
<template lang="html">
<div class="header">
<span class="back-btn" @click="goBack()">←</span>
<h6 class="header-name" v-text="navTitle"></h6>
</div>
</template>
<script>
export default {
props: {navTitle:String},
methods:{
goBack(){
history.back(-1);
}
},
}
</script>
<template lang="html">
<div class="footer">
<ul class="footer-con b2 ui-transition">
<router-link to="/movieList">
<li :class="{g1:nowTab==1}">1</li>
</router-link>
<li :class="{g1:nowTab==2}">2</li>
<li :class="{g1:nowTab==3}">3</li>
<li :class="{g1:nowTab==4}">4</li>
</ul>
</div>
</template>
<script>
export default {
props: {nowTab:Number},
}
</script>
這裡我會給底部導航欄根據nowTab設定class以顯示不同的顏色
到這裡這個簡單的專案就完成了,應該沒有漏掉什麼東西,如果不能成功的跑起來,歡迎評論問我。