構建第一個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>

 

好了,現在我們就把第一個頁面做出來了,很簡單對吧。接下來就是詳情頁了,但是在這之前我們還需要定義跳轉方式,詳細請看我另一篇文章→ Vue 路由跳轉方式 和 路由跳轉時傳參

下面就是修改後的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 我們就可以看到整個效果了

 

但是我們希望頭尾的導航欄能根據我們的頁面顯示不同的信息,這時候就需要用到通信功能了,詳情→ Vue組件通信

首先我們在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以顯示不同的顏色

 

到這裏這個簡單的項目就完成了,應該沒有漏掉什麼東西,如果不能成功的跑起來,歡迎評論問我。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章