建立項目
首先咱們要建立項目並安裝相關的組件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參數