應用 Vue Router 編程式導航經過 this.$router.push() 來實現路由跳轉。javascript
修改 src/components/Course/Course.vue 文件,給課程 div 綁定查看詳情事件。css
<div class="courseList"> <div class="detail" v-for="(course, index) in courseDetail" :key="course.id" @click="detailHandler(course.id)"> <div class="head"> <img :src="course.course_img" alt="" class="backImg"> <!-- 背景色:行內樣式優先顯示 --> <b class="mask" :style="{background: course.bgColor}"></b> <p>{{ course.name }}</p> </div>
v-on,縮寫 @ ,綁定事件監聽器。事件類型由參數指定。表達式能夠是一個方法的名字或一個內聯語句,若是沒有修飾符也能夠省略。html
methods: { // 課程詳情時間操做 detailHandler(id) { this.$router.push({ name: "course.detail", params: { detailId: id, } }) },
注意:path只能和query搭配使用,name能夠和params/query搭配使用,使用params傳參只能使用name進行引入。vue
在 src/router/index.js 添加以下內容:java
import CourseDetail from '@/components/Course/CourseDetail' // 配置路由規則 export default new Router({ linkActiveClass: 'is-active', mode: 'history', // 改成history模式 routes: [ // 略 // 課程詳情,路由:course/detail/web/3 { path: '/course/detail/web/:detailId', // 動態匹配 name: 'course.detail', // 路由名稱 component: CourseDetail // 對應組件 } ] })
要把某種模式匹配到的全部路由,所有映射到同個組件。好比這裏是課程詳情組件,可是各個不一樣的課程有不一樣的 id,且都要用這個組件來渲染。那麼能夠在vue-router的路由路徑中使用」動態路徑參數「(dynamic segment)來實現這個效果。ios
一個「路徑參數」使用冒號 :
標記。當匹配到一個路由時,參數值會被設置到 this.$route.params
,能夠在每一個組件內使用。因而,咱們能夠更新 CourseDetail
的模板,輸出當前課程的 ID:web
<template> <div> CourseID:{{$route.params.detailId}} </div> </template> <script> export default { name: "CourseDetail", data() { return { }; }, }; </script>
頁面顯示效果以下所示:vue-router
<template> <div class="wrap"> <div class="web-course-banner"> <div class="container"> <div class="title"> <img src="../../../static/images/play.png" height="67" width="67" alt=""> <h1 class="course-title">Django框架學習</h1> </div> <span class="course-text">Python語言下最強大優秀的WEB框架從入門到進階</span> <div class="course-list"> <ul> <li class="detail-item"> 難度:初級 </li> <li class="sep"></li> <li class = detail-item>時長:32小時</li> <li class="sep"></li> <li class = detail-item>學習人數:632人</li> <li class="sep"></li> <li class = detail-item>評分 10.0</li> </ul> </div> </div> </div> <!-- 代碼略 --> </div> </template> <style lang="css" scoped> .wrap{ width: 100%; } .web-course-banner{ width: 100%; height: 512px; background: url(../../../static/images/web-banner.1402933.png) no-repeat; background-size: 100% 100%; text-align: center; overflow: hidden; } .container{ width: 1200px; margin: 182px auto 0; text-align: left; } .container img{ vertical-align: middle; } .container h1{ display: inline-block; font-size: 48px; color: #4a4a4a; letter-spacing: .37px; margin-left: 40px; font-family: PingFangSC-Light; font-weight: 500; line-height: 1.1; position: relative; top: 10px; } .course-text{ width: 464px; display: inline-block; font-size: 22px; color: #4a4a4a; letter-spacing: .17px; line-height: 36px; margin-top: 33px; } .course-list{ width: 100%; } .course-list ul{ margin-top: 63px; display: flex; align-items: center; justify-content: flex-start; } .course-list ul li.detail-item{ font-size: 18px; color: #4a4a4a; letter-spacing: .74px; height: 26px; padding: 0 20px; } .course-list ul li.sep{ width: 2px; height: 14px; border-left: 1px solid #979797; } </style>
顯示效果以下所示:編程
上圖中顯示的數據都是寫死在模板中的,須要經過axios從後端獲取真實的數據信息。axios
在封裝axios的 api.js中添加新接口:
// 課程詳情頂部數據 export const coursedetailtop = (courseid)=>{ return Axios.get('coursedetailtop/?courseid=${courseid}').then(res=>res.data); };
<script> export default { name: 'CourseDetail', data(){ return { // 聲明變量存儲數據 coursedetailtop: {}, // 課程頂部詳情數據 } }, methods: { // 發送請求獲取課程詳情頂部數據 getCoursedetailtop(){ this.$http.coursedetailtop(this.$route.params.detailId) .then(res=>{ console.log(res); if(!res.error_no){ // 取非判斷沒有錯誤 this.coursedetailtop = res.data; } }) .catch(err=>{ console.log(err); }) } }, created() { this.getCoursedetailtop(); } }; </script>
查看控制檯輸出以下所示:
<div class="web-course-banner"> <div class="container"> <div class="title"> <img src="../../../static/images/play.png" height="67" width="67" alt=""> <h1 class="course-title">{{coursedetailtop.name}}</h1> </div> <span class="course-text">{{coursedetailtop.course_solgan}}</span> <div class="course-list"> <ul> <li class="detail-item"> 難度:{{coursedetailtop.level}} </li> <li class="sep"></li> <li class = detail-item>時長:{{coursedetailtop.hours}}小時</li> <li class="sep"></li> <li class = detail-item>學習人數:{{ coursedetailtop.learnnumber }}人</li> <li class="sep"></li> <li class = detail-item>評分 {{ coursedetailtop.course_review }}li> </ul> </div> </div> </div>
顯示效果以下所示:
因爲luffy網站更新,原接口已經關閉,所以更新API接口(api.js):
// 課程詳情頂部數據 export const coursedetailtop = (courseid)=>{ return Axios.get(`course/${courseid}/top/`).then(res=>res.data); }; // 課程概述 export const coursedetail = (courseid)=>{ return Axios.get(`course/${courseid}/detail/`).then(res=>res.data); };
更新 CourseDetail.vue 數據綁定:
<div class="web-course-banner"> <div class="container"> <div class="title"> <img src="../../../static/images/play.png" height="67" width="67" alt=""> <h1 class="course-title">{{coursedetailtop.name}}</h1> </div> <span class="course-text">{{coursedetailtop.course_solgan}}</span> <div class="course-list"> <ul> <li class="detail-item"> 難度:{{coursedetailtop.level}} </li> <li class="sep"></li> <li class = detail-item>課程總時長:{{coursedetailtop.numbers}}課時/{{coursedetailtop.hours}}小時</li> <li class="sep"></li> <li class = detail-item>學習人數:{{coursedetailtop.learn_number}}人</li> </ul> </div> </div> </div> <div class="course-review"> <ul class="review-head-wrap"> <li class="head-item">課程概述</li> <li class="head-item">課程章節</li> <li class="head-item">用戶評價({{coursedetailtop.review_number}})</li> <li class="head-item">常見問題</li> </ul> </div>
顯示效果:
getCourseDetail(){ this.$http.coursedetail(this.$route.params.detailId) .then(res=>{ console.log(res); // this.content = res.data.content; this.coursedetail = res.data; }) .catch(err=>{ console.log(err); }) }
<!-- 課程詳情 --> <div class="course-detail"> <div class="container"> <!-- v-html會將元素當成HTML標籤解析後輸出 --> <section class="course_item" v-html="content"></section> </div> </div> <div class="course-price"> <div class="container"> <span>能夠根據不一樣的學習狀況購買不同的學習套餐哦!</span> <ul class="course-price-item" > <li v-for="(item, index) in coursedetail.prices" :key="item.id"> <p class="price">¥{{item.price}}</p> <p class="time">有效期{{item.valid_period_name}}</p> </li> </ul> <div class="course-action"> <button class="left">購買</button> <button class="right">加入購物車</button> </div> </div> </div>
顯示效果以下所示:
點擊對應課程有效期,樣式和顏色切換。
.course-price ul li{ width: 200px; height: 112px; border: 1px solid #979797; } .course-price ul li.active{ background: #00CD23; }
給li標籤條件綁定active類樣式。同時添加點擊事件:
<ul class="course-price-item" > <li v-for="(item, index) in coursedetail.prices" :key="item.id" :class="{active:index===currentIndex}" @click="priceClick(index)"> <p class="price">¥{{item.price}}</p> <p class="time">有效期{{item.valid_period_name}}</p> </li> </ul>
在script中添加currentIndex原始數據和click點擊事件:
<script> export default { name: 'CourseDetail', data(){ return { // 聲明變量存儲數據 coursedetailtop: {}, // 課程頂部詳情數據 content: "", // currentIndex: 0, // 爲0時,頁面刷新默認選擇了第一項 currentIndex: null // 默認不選擇 } }, methods: { priceClick(index){ this.currentIndex = index; }, // 代碼略 }, created() { this.getCoursedetailtop(); this.getCourseDetail(); } }; </script>
點擊效果以下所示:
ref 加在普通的元素上,可用 this.ref.name 獲取到的是dom元素。
<ul class="course-price-item" > <li v-for="(item, index) in coursedetail.prices" :key="item.id" :class="{active:index===currentIndex}" @click="priceClick(index)"> <p class="price" ref="price">¥{{item.price}}</p> <p class="time" ref="time">有效期{{item.valid_period_name}}</p> </li> </ul>
經過js來操做dom:
methods: { priceClick(index){ this.currentIndex = index; this.$refs.price[index].style.color = '#fff'; this.$refs.time[index].style.color = '#fff'; },
傳給 v-bind:class
一個對象,以動態地切換 class :
<div class="course-price"> <div class="container"> <span>能夠根據不一樣的學習狀況購買不同的學習套餐哦!</span> <ul class="course-price-item" > <li v-for="(item, index) in coursedetail.prices" :key="item.id" :class="{active:index===currentIndex}" @click="priceClick(index)"> <p class="price" :class="{active:index===currentIndex}">¥{{item.price}}</p> <p class="time" :class="{active:index===currentIndex}">有效期{{item.valid_period_name}}</p> </li> </ul> <div class="course-action"> <button class="left">購買</button> <button class="right">加入購物車</button> </div> </div> </div>
上面語法表示 active 這個 class 存在與否取決於數據屬性 index===currentIndex 的true/false。
添加點擊項字體的 active 樣式:
.course-price ul li p.active { color: #fff; }
如此,點擊後會將點擊項字體從黑色變成白色,優化顯示效果。
添加購物車時,須要判斷是否點選了課程套餐,沒有點選課程套餐應提示錯誤信息。還須要判斷用戶是否登陸,若用戶未登陸須要跳轉到登陸頁面。
在購物車標籤中添加點擊事件:
<div class="course-action"> <button class="left">購買</button> <button class="right" @click="addShopCart">加入購物車</button> </div>
添加addShopCart方法:
<script> export default { name: 'CourseDetail', data(){ return { // 聲明變量存儲數據 coursedetailtop: {}, // 課程頂部詳情數據 content: "", // currentIndex: 0, // 爲0時,頁面刷新默認選擇了第一項 currentIndex: null // 默認不選擇 } }, methods: { // 加入購物車事件 addShopCart(){ if(this.currentIndex){ // 判斷當前currentIndex是否有值 } else { } }, // 代碼略 }; </script>
這裏將 currentIndex的默認值從0修改成null,這是由於若是默認爲0,則默認選擇了第一項,無需再提示未選中套餐。修改成 null 後,則是默認沒有選擇,所以能夠經過 this.currentIndex 來斷定當前是否選中了套餐。
在沒有選擇套餐時點擊添加購物車提示錯誤消息。這裏採用element組件中 Message消息提示 來實現錯誤提示。
methods: { // 加入購物車事件 addShopCart(){ if(this.currentIndex){ // 判斷當前currentIndex是否有值 } else { // element組件錯誤提示 this.$message({ message: '您尚未選擇要加入的套餐哦!', center: true // 使用 center 屬性讓文字水平居中 }); } },
Element 註冊了一個$message
方法用於調用,Message 能夠接收一個字符串或一個 VNode 做爲參數,它會被顯示爲正文內容。
使用 center
屬性讓文字水平居中。
用戶點擊購物車須要優先判斷是不是登陸用戶,若是沒有登陸先跳轉到登陸頁面。
用戶名、密碼保存,自動登陸等,能夠經過設置cookie實現,第一次登陸網站後在本地計算機的中寫入cookie,以後再次登陸此網站查看cookie中現有的值,用cookie值進行網站登陸便可。可是 cookie 不適合大量數據的存儲,由於它們由每一個對服務器的請求來傳遞,這使得 cookie 速度很慢並且效率也不高。
HTML5提供了一個此類問題比較方便的解決方案,就是localstorage。數據不是由每一個服務器請求傳遞的,而是隻有在請求時使用數據。它使在不影響網站性能的狀況下存儲大量數據成爲可能。對於不一樣的網站,數據存儲於不一樣的區域,而且一個網站只能訪問其自身的數據。HTML5 使用 JavaScript 來存儲和訪問數據。
所以可使用 window.localStorage.getItem('token') 來判斷用戶是否登陸。
methods: { // 加入購物車事件 addShopCart(){ if(this.currentIndex){ // 判斷當前currentIndex是否有值 if(window.localStorage.getItem('token')){ // 判斷用戶是否登陸 // 添加到購物車 } else { // 跳轉登陸頁面 // 使用編程式導航來跳轉 this.$router.push({ name: 'Login', query: { // window.location 只讀屬性,返回一個 Location 對象,其中包含有關文檔當前位置的信息 return_url: window.location.href, // 將當前頁面地址做爲查詢參數 } }) } } else { // element組件錯誤提示 this.$message({ message: '您尚未選擇要加入的套餐哦!', center: true // 使用 center 屬性讓文字水平居中 }); } },
在 Vue 實例內部,你能夠經過 $router
訪問路由實例。所以你能夠調用 this.$router.push。
在index.js中引入Login組件並配置路由信息:
import Login from '@/components/Login/Login' Vue.use(Router) // 配置路由規則 export default new Router({ linkActiveClass: 'is-active', mode: 'history', // 改成history模式 routes: [ // 代碼略 { path: '/login', name: 'Login', component: Login // Login 組件 } ] })
添加 src/components/Login/Login.vue 組件。
<template> <div class="box"> <img src="https://www.luffycity.com/static/img/Loginbg.3377d0c.jpg" alt=""> <div class="login"> <div class="login-title"> <img src="https://www.luffycity.com/static/img/Logotitle.1ba5466.png" alt=""> <p>幫助有志向的年輕人經過努力學習得到體面的工做和生活!</p> </div> <div class="login_box"> <div class="title"> <span>密碼登陸</span> <span>短信登陸</span> </div> <div class="inp"> <input v-model = 'username' type="text" placeholder="用戶名 / 手機號碼" class="user"> <input v-model = 'password' type="password" name="" class="pwd" placeholder="密碼"> <div id="geetest"></div> <div class="rember"> <p> <input type="checkbox" class="no" name="a"></input> <span>記住密碼</span> </p> <p>忘記密碼</p> </div> <button class="login_btn">登陸</button> <p class="go_login" >沒有帳號 <span>當即註冊</span></p> </div> </div> </div> </div> </template> <script> export default { name: 'Login', data(){ return { username: "", password: "" } } }; </script>
顯示效果以下所示: