前端Vue項目——課程詳情頁面實現

1、詳情頁面路由跳轉

  應用 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

  

2、課程詳情頁面實現

一、課程詳情頂部佈局和樣式

<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

(1)添加課程詳情頂部接口

  在封裝axios的 api.js中添加新接口:

// 課程詳情頂部數據
export const coursedetailtop = (courseid)=>{
  return Axios.get('coursedetailtop/?courseid=${courseid}').then(res=>res.data);
};

(2)發送請求獲取數據及綁定數據

<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新接口

  因爲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>

  顯示效果:

  

3、課程詳情套餐區實現

一、更新課程詳情返回數據

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>

  顯示效果以下所示:

  

三、點選課程樣式切換

  點擊對應課程有效期,樣式和顏色切換。

 (1)定義li標籤樣式

  .course-price ul li{
    width: 200px;
    height: 112px;
    border: 1px solid #979797;
  }
  .course-price ul li.active{
    background: #00CD23;
  }

(2)動態綁定樣式

   給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>

  點擊效果以下所示:

  

四、經過dom修改點擊項字體和顏色(不推薦)

   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;
  }

  如此,點擊後會將點擊項字體從黑色變成白色,優化顯示效果。

  

4、課程購物車實現

  添加購物車時,須要判斷是否點選了課程套餐,沒有點選課程套餐應提示錯誤信息。還須要判斷用戶是否登陸,若用戶未登陸須要跳轉到登陸頁面。

一、購物車點擊事件

  在購物車標籤中添加點擊事件:

<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 屬性讓文字水平居中。

三、點擊購物車進入登陸頁面

  用戶點擊購物車須要優先判斷是不是登陸用戶,若是沒有登陸先跳轉到登陸頁面。

(1)利用html本地存儲功能實現登陸用戶信息保存  

  用戶名、密碼保存,自動登陸等,能夠經過設置cookie實現,第一次登陸網站後在本地計算機的中寫入cookie,以後再次登陸此網站查看cookie中現有的值,用cookie值進行網站登陸便可。可是 cookie 不適合大量數據的存儲,由於它們由每一個對服務器的請求來傳遞,這使得 cookie 速度很慢並且效率也不高。

  HTML5提供了一個此類問題比較方便的解決方案,就是localstorage。數據不是由每一個服務器請求傳遞的,而是隻有在請求時使用數據。它使在不影響網站性能的狀況下存儲大量數據成爲可能。對於不一樣的網站,數據存儲於不一樣的區域,而且一個網站只能訪問其自身的數據。HTML5 使用 JavaScript 來存儲和訪問數據。

  

  所以可使用 window.localStorage.getItem('token') 來判斷用戶是否登陸。

(2)使用vue編程式導航跳轉

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。

(3)添加Login組件和路由

  在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>

  顯示效果以下所示:

  

相關文章
相關標籤/搜索