路飛學城前端Vue

路飛學城前端Vue

建立項目

首先咱們要建立項目並安裝相關的組件html

複製代碼
1. vue init webpack luffy

2. 安裝依賴:
    cd luffy
        npm install vuex --save            用於:多組件之間數據共享
        npm install vue-cookies --save  用於:操做cookie
        npm install axios --save        用於:發送ajax請求

3. 快速使用
    程序入口(manage.py):
        App.vue 
            - 組件名稱【組件1(/index ),組件2(/course),組件3】
            - 空容器
        main.js 
        
    路由(urls.py):
        router/index.js 
            /index    Course1.vue
            /course   Course2.vue
    組件(views):
        Course1.vue  (每一個py文件)
        Course2.vue  (每一個py文件)
        Course3.vue  (每一個py文件)
複製代碼

建立基本的路由和組件

首先咱們要在App.vue中展示一些基本的組件,須要建立路由和相關的組件前端

index.jsvue

複製代碼
import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/components/Index'
import Course from '@/components/Course'
import Detail from '@/components/Detail'
import Micro from '@/components/Micro'
import News from '@/components/News'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'index',
      component: Index
    },
    {
      path: '/course',
      name: 'course',
      component: Course
    },
    {
      path: '/detail/:cid',
      name: 'detail',
      component: Detail
    },
    {
      path: '/micro',
      name: 'micro',
      component: Micro
    },
    {
      path: '/news',
      name: 'news',
      component: News
    }
  ],
  mode:'history'
})
複製代碼

mode:'history'參數能夠去掉url中的#號webpack

App.vueios

複製代碼
<template>
  <div id="app">
    <div>
      <router-link to="/">首頁</router-link>
      <router-link to="/course">課程</router-link>
      <router-link to="/micro">學位課</router-link>
      <router-link to="/news">深科技</router-link>
    </div>
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>

</style>
複製代碼

這樣咱們就能夠在頁面上經過點擊來切換路由和組件了web

展現課程列表

當咱們點擊course組件時應該能看到課程列表,因此在course組件中咱們須要向後頭髮送ajax請求,獲取課程的數據,並使用v-for顯示到頁面上ajax

course.vuevue-router

複製代碼
<template>
  <div>
    <h1>{{msg}}</h1>
    <div v-for="item in courseList">
      <!--<router-link to="/detail">{{item.id}} {{item.name}} <img class="img" v-bind:src="item.img" alt=""></router-link>-->
      <!--<router-link :to="{path: '/detail/'+item.id }">{{item.id}} {{item.name}} <img class="img" v-bind:src="item.img" alt=""></router-link>-->
      <router-link :to="{ name:'detail',params:{cid:item.id} }">{{item.id}} {{item.name}} <img class="img" v-bind:src="item.img" alt=""></router-link>
    </div>
  </div>
</template>

<script>
  export default {
    name: "Course",
    data(){
      return {
        msg:'課程列表',
        courseList:[]
      }
    },
    mounted(){
      this.init()
    },
    methods:{
      init(){
        // 發送Ajax
        this.courseList = [
          {id:11,name:'21天學會Python',img: require('../assets/logo.png')},
          {id:21,name:'21天學會Java',img:require('../assets/logo.png')},
          {id:31,name:'21天學會Linux',img:require('../assets/logo.png')},
        ]
      }
    }

  }
</script>

<style scoped>
  .img{
    width: 30px;
    height: 30px;
  }
</style>
複製代碼

這裏咱們先不發送ajax請求了,直接模擬了數據,在定義圖片的src屬性時,能夠直接寫上圖片的路徑,可是若是像上面那樣使用綁定屬性時,可能會看不到圖片,這時須要使用require,img: require('../assets/logo.png'),這樣就能正常看到圖片了vuex

顯示課程詳細

在course組件中咱們經過v-for的方式展現了課程列表,如今咱們須要經過點擊某一門課程來看到它的詳細信息,首先咱們要在路由中定義一個Detail組件npm

{
      path: '/detail/:cid',
      name: 'detail',
      component: Detail
    },

因爲須要某一門課的詳細信息,因此須要知道這門課的id,在路徑中咱們在/detail後加了:cid來區分id,這裏的cid能夠換成其它的,在course中咱們經過router-link來點擊跳轉

複製代碼
<div v-for="item in courseList">
      <!--<router-link to="/detail">{{item.id}} {{item.name}} <img class="img" v-bind:src="item.img" alt=""></router-link>-->
      <!--<router-link :to="{path: '/detail/'+item.id }">{{item.id}} {{item.name}} <img class="img" v-bind:src="item.img" alt=""></router-link>-->
      <router-link :to="{ name:'detail',params:{cid:item.id} }">{{item.id}} {{item.name}} <img class="img" v-bind:src="item.img" alt=""></router-link>
    </div>
複製代碼

這裏的to屬性咱們能夠經過綁定方法來定義:

第一種方式是經過:to="{path: '/detail/'+item.id }",經過path再拼接id的形式來實現

第二種方式是經過:to="{ name:'detail',params:{cid:item.id} }",經過name來肯定url,並經過params來肯定url的參數

經過上面的兩種方式咱們均可以訪問到Detail組件

Detail.vue

複製代碼
<template>
    <div>
      <h1>課程詳細 - {{currentCourseId}}</h1>
      <ul>
        <li>課程名稱: {{courseDetail.title}}</li>
        <li>課程簡介: {{courseDetail.summary}}</li>
      </ul>

      <h1>推薦課程</h1>
      <ul v-for="item in courseDetail.recommends">
          <li v-on:click="recommendCourse(item.id)">{{item.name}}</li>
          <!--<router-link :to="{name:'detail',params:{cid:item.id}}">{{item.name}}</router-link>-->
      </ul>
    </div>
</template>

<script>
    export default {
        name: "detail",
      data(){
          return {
            currentCourseId:this.$route.params.cid,
            courseDetail:{
              title: '',
              summary:'',
              recommends:[]
            }
          }
      },
      mounted(){
        this.init()
      },
      methods:{
          init(){
            // 根據當前ID發送Ajax請求,獲取課程詳細信息 this.currentCourseId
            this.courseDetail = {
              title: '21天學會Python'+this.currentCourseId,
              summary:'休想休想休想休想休想休想休想休想休想',
              recommends:[
                {id:100,name:'rest api'},
                {id:200,name:'vue'}
              ]
            }
          },
        recommendCourse(cid){
            // 主動將內容根據最新的課程ID進行更新
            this.currentCourseId = cid
            this.init()
            // URL進行重定向
            this.$router.push({name:'detail',params:{cid:cid}})
        }
      }
    }
</script>

<style scoped>

</style>
複製代碼

在詳細頁中咱們能夠經過this.$route.params.cid來獲取url中的參數,也就是課程的id值,經過這個id咱們能夠向後端發送ajax請求來獲取數據,並在頁面上顯示,在這裏咱們要注意一點,在課程詳細中包含有推薦課程,點擊推薦課程咱們應該能看到推薦課程的詳細

信息,可是若是還使用上面的方法,也就是<router-link :to="{name:'detail',params:{cid:item.id}}">{{item.name}}</router-link>,因爲都是在Detail組件中,因此這時點擊它,頁面是不會變化的,只能看到url的變化,因此在這裏咱們給推薦課程的標籤綁定了一個事件,

點擊後會修改this.currentCourseId爲推薦課程的id,而後再次進行初始化(發送ajax請求),這樣就能獲取到推薦課程的數據並顯示到頁面上,可是這樣只是頁面內容變了,url沒有變,因此咱們還要用this.$router.push({name:'detail',params:{cid:cid}})來進行url

重定向

相關命令

this.$route.params  獲取url中的參數
this.$router.push()  url重定向,跳轉

利用vuex和vue-cookies實現用戶登陸、註銷

登陸按鈕應該在每一個頁面都能看到,因此咱們將組件放到App.vue中,首先建立路由

{
      path: '/login',
      name: 'login',
      component: Login
    }

Login.vue

複製代碼
<template>
    <div>
      <input type="text" v-model="username" placeholder="用戶名">
      <input type="text" v-model="password" placeholder="密碼">
      <input type="button" value="登陸" v-on:click="doLogin"> {{error}}
    </div>
</template>

<script>
    export default {
        name: "Login",
      data(){
          return {
            username:'',
            password:'',
            error:''
          }
      },
      methods:{
          doLogin(){
            if(this.username === 'alex' && this.password === '123'){
                this.$store.commit('saveToken',{username:'alex',token:'sdfsdfsdf'})
                this.$router.push({name:'index'})
            }else{
              this.error = '用戶名或密碼錯誤'
            }

          }
      }
    }
</script>

<style scoped>

</style>
複製代碼

在這個組件中咱們經過v-model來進行數據的雙向綁定,當用戶輸入了用戶名和密碼點擊登陸後,咱們應該拿到數據,併發送給後端進行驗證,這裏咱們在前端簡單驗證一下,就不發送後端了,當驗證成功後咱們跳轉到index首頁,驗證失敗則顯示錯誤信息,這裏咱們

其實還調用了$store中的一個方法,這個後面再說

組件寫完後咱們就能夠把他加到App.vue中了

複製代碼
<template>
  <div id="app">
    <div>
      <router-link to="/">首頁</router-link>
      <router-link to="/course">課程</router-link>
      <router-link to="/micro">學位課</router-link>
      <router-link to="/news">深科技</router-link>

      <div v-if="this.$store.state.username">
        <a>{{this.$store.state.username}}</a>
        <a v-on:click="doLogout">註銷</a>
      </div>
      <div v-else>
        <router-link to="/login">登陸</router-link>
      </div>


    </div>
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods:{
    doLogout(){
        this.$store.commit('clearToken')
    }
  }
}
</script>

<style>

</style>
複製代碼

這裏咱們能夠看到在App.vue中作了一步判斷,其實就是爲了實現當用戶沒有登陸時,能夠看到登陸按鈕,若是用戶登陸了就能看到本身的用戶名和註銷按鈕,要實現這個功能必需要咱們的App.vue能使用到Login組件中的用戶登陸信息,因此這裏咱們使用vuex來實現

首先導入vuex並生成store對象

複製代碼
import Vue from 'vue'
import Vuex from 'vuex'
import Cookie from 'vue-cookies'

Vue.use(Vuex)

export default new Vuex.Store({
  // 組件中經過 this.$store.state.username 調用
  state: {
    username: Cookie.get('username'),
    token: Cookie.get('token'),
    apiList: {
      auth: 'http://127.0.0.1:8000/api/v1/auth/',
      courses: 'http://127.0.0.1:8000/api/v1/courses/',
      pricePolicy: 'http://127.0.0.1:8000/api/v1/price_policy/',
      shopCar: 'http://127.0.0.1:8000/api/v1/shop_car/',
    }
  },
  mutations: {
    // 組件中經過 this.$store.commit('saveToken',{username:'alex',token:'sdfsdfsdf'})  調用
    saveToken: function (state, userToken) {
      state.username = userToken.username;
      state.token = userToken.token;

      Cookie.set("username", userToken.username, "20min")
      Cookie.set("token", userToken.token, "20min")

    },
    clearToken: function (state) {
      state.username = undefined
      state.token = undefined

      Cookie.remove('username')
      Cookie.remove('token')

    }
  }
})
複製代碼

能夠看到這裏state中定義了username和token,當用戶登陸後咱們應該將這兩個信息保存,並寫到cookie中,因此在mutations中咱們定義了一個方法saveToken,當用戶登陸成後咱們就能夠調用這個方法來將username和token寫到cookie中

Cookie.set("username", userToken.username, "20min")
Cookie.set("token", userToken.token, "20min")

而後state中的username和token能夠直接從cookie中獲取

username: Cookie.get('username'),
token: Cookie.get('token'),

注意,這裏若是不從cookie中獲取,而是寫死的話,頁面刷新後可能就取不到原來的值了,這樣在App.vue中咱們就能夠判斷state.username是否存在,來顯示登陸按鈕或用戶信息,當顯示用戶信息時,還有一個註銷按鈕,咱們給它綁定一個點擊事件,當點擊時,執行

mutations中的clearToken方法,註銷cookie

state.username = undefined
state.token = undefined

Cookie.remove('username')
Cookie.remove('token')

課程詳細頁面:tab切換

在課程詳細頁中咱們能夠經過點擊切換一些顯示的內容,以下圖所示

這裏咱們能夠給這些標籤都綁定一個點擊事件,而後經過v-show來實現

複製代碼
<h1>tab切換</h1>
<div class="tab-menu">
  <div>
    <a v-on:click="changeTab('detail')">課程概述</a>
    <a v-on:click="changeTab('chapter')">課程章節</a>
    <a v-on:click="changeTab('review')">用戶評價</a>
    <a v-on:click="changeTab('question')">常見問題</a>
  </div>
</div>

<div>
  <div v-show="tabs.detail">課程概述內容</div>
  <div v-show="tabs.chapter">課程章節內容</div>
  <div v-show="tabs.review">用戶評價內容</div>
  <div v-show="tabs.question">常見問題內容</div>
</div>
複製代碼

這裏的詳細內容也應該經過ajax請求從後臺獲取,這裏咱們直接寫死了

tabs數據

tabs: {
  detail: true,
  chapter: false, //chapter
  review: false,
  question: false,
},

changeTab方法

複製代碼
   changeTab(name) {
     for (let item in this.tabs) {
       if (item === name) {
         this.tabs[item] = true
       } else {
         this.tabs[item] = false
       }
     }
 },
複製代碼

點擊某一個時就將其對應的tabs中的值變爲true,其它的變爲false,這樣經過v-show就能將點擊的內容顯示出來

咱們用到的式樣

複製代碼
.tab-menu {
    border-bottom: 1px solid #ddd;
    padding-top: 30px;
    text-align: center;
  }

  .tab-menu a {
    display: inline-block;
    padding: 20px;
    border-bottom: 2px solid transparent;
    cursor: pointer;
  }

  .tab-menu a:hover {
    border-bottom: 2px solid darkseagreen;
  }
複製代碼

價格策略效果

在課程詳細頁中咱們還應該顯示頁面的價格策略

複製代碼
<h1>價格策略</h1>
      <ul class="price-policy">
        <li v-bind:class="[{active:num==selectCourseIndex} ]" v-on:click="choiceCourse(num)" v-for="(pri,num) in prices">¥{{pri.price}} (有效期 {{pri.period}} )
        </li>
      </ul>
複製代碼

這裏的prices數據咱們本身模擬,就不存後端拿了,而後給每一個標籤綁定一個點擊事件,點擊時將selectCourseIndex的值改成當前標籤的索引,這樣當前的標籤就能得到一個active的class屬性

複製代碼
prices: [
  {id: 11, price: 100, period: '2個月'},
  {id: 21, price: 200, period: '3個月'},
  {id: 31, price: 300, period: '4個月'},
]


choiceCourse(index) {
  this.selectCourseIndex = index
}
複製代碼

active樣式

.price-policy .active {
    background-color: darkseagreen;
  }

播放cc視頻

在cc視頻上傳了視頻後cc視頻會給咱們一段html代碼,咱們只要把他複製到咱們的頁面上就能夠了

在課程詳細頁組件中

複製代碼
<h1>視頻描述</h1>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
        codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0"
        width="400" height="300" v-bind:id="'cc_'+video_brief_link">
  <param name="movie"
         v-bind:value="'https://p.bokecc.com/flash/single/C2401FCB0F73D923_'+video_brief_link + 
  <param name="allowFullScreen" value="true"/>
  <param name="allowScriptAccess" value="always"/>
  <param value="transparent" name="wmode"/>
  <embed
    v-bind:src="'https://p.bokecc.com/flash/single/C2401FCB0F73D923_'+video_brief_link + '_false_35E7C8085202EBC3_1/player.swf'"
    width="400" height="300" name="cc_ECC9954677D8E1079C33DC5901307461" allowFullScreen="true"
    wmode="transparent" allowScriptAccess="always" pluginspage="http://www.macromedia.com/go/getflashplayer"
    type="application/x-shockwave-flash"/>
</object>
複製代碼

其中的video_brief_link參數就是cc提供的一段字符串,咱們能夠在data中定義

video_brief_link: 'ECC9954677D8E1079C33DC5901307461'

基於router的攔截器實現用戶登陸成功後才能訪問頁面

router有一個功能相似於django中的中間件,能夠在訪問某一個url前寫一些邏輯,這裏咱們用來實現一些頁面的訪問控制,對於一些頁面,咱們只給登陸後的用戶訪問,未登陸的則直接跳轉到登陸頁面

main.js

複製代碼
router.beforeEach(function (to,from,next) {

    if(to.meta.requireAuth){
      // 須要登陸的路由
      if (store.state.token) {
        // 已經登陸
        next()
      } else {
        // 未登陸
        next({
          name: 'login'
        })
      }
    }else{
      // 不須要登陸的路由
      next()
    }
  }
)
複製代碼

router.beforeEach就是在訪問url前會執行的方法,這裏的function有3個參數,to from next,to表示要訪問的url,from表示從哪一個url來,next是接下來實際會訪問的url,通常狀況下next和to是同樣的

這裏咱們判斷用戶是否登陸了,可是不能對每一個頁面都判斷,只有一些特定的頁面須要作這個判斷,這時咱們就能夠在url中添加一些參數了

複製代碼
{
      path: '/micro',
      name: 'micro',
      component: Micro,
       meta:{
        requireAuth:true,
      }
    },
複製代碼

對於須要登陸才能訪問的url咱們能夠加一個meta參數,裏面有一個requireAuth爲true,在router.beforeEach咱們就能夠先判斷to.meta.requireAuth,若是爲true說明須要登陸後才能訪問,而後再判斷token是否存在,存在表示已經登陸,則直接next(),不存在則跳轉到

登陸頁面next({ name: 'login' })

 

二級路由

前面咱們用的都是一級路由,如今咱們來使用一次二級路由

複製代碼
{
  path: '/help',
  name: 'help',
  component: Help,
  children: [
    {
      path: 'about-us',
      name: 'about-us',
      component: AboutUs
    },
    {
      path: 'user-note',
      name: 'user-note',
      component: UserNote
    },
    {
      path: 'feedback',
      name: 'feedback',
      component: Feedback
    }
  ]
}
複製代碼

首先先寫一個一級路由help,而後加一個children屬性,裏面寫二級路由,注意,這裏二級路由的path前面不要加/

寫一級路由組件

複製代碼
<template>
    <div>
        <h2>{{msg}}</h2>
        
        預留二級路由的位置
        <router-view></router-view>
    </div>
</template>
複製代碼

注意在一級路由組件中須要給二級路由預留位置<router-view></router-view>

寫二級路由

<template>
    <div>
        <h2>{{msg}}</h2>
    </div>
</template>

使用

<router-link to="/help/about-us">關於咱們</router-link>
<router-link to="/help/feedback">用戶反饋</router-link>
<router-link to="/help/user-note">使用手冊</router-link>

點擊後就能看到在頁面上有一級路由組件的內容,而且內容中還包含有二級路由組件的內容

訪問登陸頁面時,添加backurl

爲了提升用戶體驗,當咱們訪問登陸頁面登陸成功後,應該跳轉回以前的頁面,而不該該老是跳轉到首頁,咱們能夠經過在訪問login的url時添加backurl參數來實現

首先咱們要修改登陸按鈕的to屬性

<router-link v-else :to="{name:'login',query:{backUrl: this.$route.path}}">登陸</router-link>

這裏咱們增長了一個query屬性,這個屬性就是在url後加?k1=v1這類的參數的,而後咱們經過this.$route.path取到當前頁的url,並添加到backUrl參數中

在登陸組件中,登陸成功後咱們要取到backUrl屬性並判斷

複製代碼
methods: {
  doLogin() {
    if (this.username === 'oldboy' && this.password === '123') {
      let obj = {username: 'oldboy', token: 'jsudfnksdjwe8234sdfsdkf'}
      this.$store.commit('saveToken', obj)
      let backUrl = this.$route.query.backUrl
      if (backUrl) {
        this.$router.push({path: backUrl})
      } else {
        this.$router.push('/index')
      }
    } else {
      this.error = '用戶名或祕密錯誤'
    }
  }
複製代碼

經過this.$route.query取到url中的參數backUrl,並判斷是否存在,若是存在則使用this.$router.push({path: backUrl})跳轉回原來的頁面,不存在則跳轉首頁

在router攔截器中咱們也應該實現這個功能

複製代碼
router.beforeEach(function (to, from, next) {
  if (to.meta.requireAuth) {
    if (store.state.token) {
      next()
    } else {
      next({
        path: '/login',
        query: {backUrl: to.fullPath}
      })
    }
  } else {
    next()
  }

})
複製代碼

當要跳轉登陸頁面時須要加backUrl參數

相關文章
相關標籤/搜索