學(xué)習(xí)功能,課程詳情與視頻

學(xué)習(xí)功能組件準(zhǔn)備

整體分為上中下三部分甩鳄,頂部為標(biāo)題逞度,中間為學(xué)習(xí)課程列表,底部為導(dǎo)航
那么我們就首先引入LayoutFooter組件

// learn/index.vue
<template>
  <div class="learn">
    <!-- 頂部功能 -->
    <!-- 底部導(dǎo)航 -->
    <layout-footer></layout-footer>
  </div>
</template>

<script>
import LayoutFooter from '@/components/LayoutFooter'
export default {
  name: 'Learn',
  components: {
    LayoutFooter
  }
}
</script>

頭部功能

設(shè)置NarBar進(jìn)行標(biāo)題顯示就可以了

...
    <!-- 頂部功能 -->
    <van-nav-bar title="已購課程"></van-nav-bar>
...

課程列表公共組件

頂部列表與Course中使用的CourseContentList組件列表是非常類似的妙啃,我們可以把它封裝成公共組件來減少工作量
Course顯示的是所有的課程档泽,而學(xué)習(xí)展示的則是用于已經(jīng)購買的課程,數(shù)據(jù)不同揖赴,但是結(jié)構(gòu)相同
這里將CourseContentList.vue作為公共組件移動到src/components 中
那么要注意:CourseContent中對于CourseContentList的引入路徑要隨之修改

// course/components/CourseContent.vue
...
import CourseContentList from '@/components/CourseContentList'
...

引入組件:

...
    <!-- 課程列表 -->
    <course-content-list></course-content-list>
...

<script>
...
import CourseContentList from '@/components/CourseContentList'
export default {
  name: 'Learn',
  components: {
...
    CourseContentList
  }
}
</script>

// 同理馆匿,要保持頂部和底部的距離,防止覆蓋一部分內(nèi)容
<style lang="scss" scoped>
.course-content-list {
  top: 50px;
  bottom: 50px;
}
</style>

接口抽離

課程列表組件初始設(shè)置時使用的是所有課程接口燥滑,如果我們改為其他的數(shù)據(jù)(已購課程)渐北,那么應(yīng)當(dāng)由父組件進(jìn)行接口設(shè)置,再將其傳入子組件铭拧,由子組件在適當(dāng)?shù)臅r機(jī)進(jìn)行調(diào)用
修改我們的CourseContentList.vue
(+赃蛛、-表示當(dāng)前行代碼我們應(yīng)該去除還是新加)

<script>
// CourseContentList.vue
...
-import { getQueryCourses } from '@/services/course'
...
+props: {
+  // 用于請求數(shù)據(jù)的函數(shù)
+  fetchData: {
+    type: Function,
+    required: true
+  }
+},
...
async onRefresh () {
    ...
-  // 重新請求數(shù)據(jù)
-  const { data } = await getQueryCourses({
+  const { data } = await this.fetchData({
  ...
},
async onLoad () {
+  const { data } = await getQueryCourses({
-  const { data } = await this.fetchData({
...
}

修改CourseContent.vue

// CourseContent.vue
...
<course-content-list
+  :fetchData="fetchData"
></course-content-list>
...
-import { getAllAds } from '@/services/course'
+import { getAllAds, getQueryCourses } from '@/services/course'
...
methods: {
  // 傳入請求
+  fetchData (options) {
+    return getQueryCourses(options)
+  },
...

學(xué)習(xí)組件處理

封裝接口

這里我們使用已經(jīng)獲取已購課程接口:接口

// 獲取已購課程信息
export const getPurchaseCourse = () => {
  return request({
    method: 'GET',
    url: '/front/course/getPurchaseCourse'
  })
}

引入到頁面中,并給子組件發(fā)送請求方法名


數(shù)據(jù)綁定改進(jìn)

由于所有課程接口和已購課程接口響應(yīng)的數(shù)據(jù)格式不同搀菩,在進(jìn)行數(shù)據(jù)綁定時需要進(jìn)行檢測

  • 響應(yīng)數(shù)據(jù)的格式
    • 所有課程為:data.data.records
    • 已購課程為:data.content
  • 數(shù)據(jù)對應(yīng)的鍵不同
    • 課程名稱不同
    • 圖片不同
    • 已購課程沒有價格相關(guān)數(shù)據(jù)
      那么我們根據(jù)以上的條件可以進(jìn)行代碼的改進(jìn)焊虏,比如加上||判斷,加上v-if控制顯示
        <van-cell
        v-for="item in list"
        :key="item.id">
        <!-- 課程左側(cè)圖片 -->
        <div>
          <!-- 所有課程與已購課程圖片數(shù)據(jù)屬性名不同秕磷,檢測使用 -->
            <img :src="item.courseImgUrl || item.image">
        </div>
        <!-- 課程右側(cè)信息 -->
        <div class="course-info">
          <!-- 名稱檢測 -->
            <h3 v-text="item.courseName || item.name"></h3>
            <p v-html="item.previewFirstField" class="course-preview"></p>
            <!-- 如果為已購,無需再顯示價格區(qū)域 -->
            <p class="price-container" v-if="item.price">
                <span class="course-discount">¥{{ item.discounts }}</span>
                <s class="course-price">¥{{ item.price }}</s>
            </p>
        </div>
        </van-cell>

響應(yīng)數(shù)據(jù)格式檢測:

// CourseContentList.js 響應(yīng)數(shù)據(jù)格式檢測
...
  async onRefresh () {
    ...
    // 如果存在數(shù)據(jù)炼团,清空并課程數(shù)據(jù)澎嚣,否則結(jié)束
    if (data.data && data.data.records && data.data.records.length !== 0) {
      this.list = data.data.records
+    } else if (data.content && data.content.length !== 0) {
+      this.list = data.content
    }
    ...
  },
  async onLoad () {
        ...
    // 檢測疏尿,如果沒有數(shù)據(jù)了,結(jié)束易桃,如果有褥琐,保存
    if (data.data && data.data.records && data.data.records.length !== 0) {
      this.list.push(...data.data.records)
+    } else if (data.content && data.content.length !== 0) {
+      this.list.push(...data.content)
    }
        ...
    // 數(shù)據(jù)全部加載完成
+    if (data.data && data.data.records && data.data.records.length < 10) {
      this.finished = true
+    } else if (data.content && data.content.length < 10) {
+      this.finished = true
    }
  }
}
...

課程詳情

組件準(zhǔn)備
創(chuàng)建src/views/course-info/index.vue,在組件中要通過props接收路徑傳參

<template>
  <div class="course-info">課程內(nèi)容的id:{{ courseId }}</div>
</template>

<script>
export default {
  name: 'CourseInfo',
  props: {
    courseId: {
      type: [String, Number],
      required: true
    }
  }
}
</script>

<style lang="scss" scoped>

</style>

設(shè)置路由規(guī)則

// router/index.js
...
  {
    path: '/course-info/:courseId/',
    name: 'course-info',
    component: () => import(/* webpackChunkName: 'course-info' */'@/views/course/info'),
    props: true
  },
...

設(shè)置跳轉(zhuǎn)

// course/components/CourseContentList.vue
...
<van-cell
  v-for="item in list"
  ...
  @click="$router.push({
    name: 'course-info',
    params: {
      courseId: item.id
    }
  })"
>
...

接口封裝

使用接口:獲取課程詳情接口

// 獲取課程詳情信息
export const getCourseById = params => {
  return request({
    method: 'GET',
    url: '/front/course/getCourseById',
    params
  })
}

引入到頁面晤郑,并且發(fā)送請求驗(yàn)證沒有問題

// course-info/index.vue
...
<script>
import { getCourseById } from '@/services/course'

export default {
  ...
  data () {
    return {
      // 課程信息
      course: {}
    }
  },
  created () {
    this.loadCourse()
  },
  methods: {
    async loadCourse () {
      const { data } = await getCourseById({
        courseId: this.courseId
      })
      this.course = data.content
      console.log(data)
    }
  }
}
</script>

<style lang="scss" scoped></style>

主體內(nèi)容區(qū)域處理

整體采用Vant的cell單元格處理

// course-info/index.vue
<template>
  <div class="course-info">
    <van-cell-group>
      <!-- 課程圖片 -->
      <van-cell class="course-img"></van-cell>
      <!-- 課程描述 -->
      <van-cell class="course-desctription"></van-cell>
        <!-- 課程詳細(xì)內(nèi)容 -->
      <van-cell class="course-detail"></van-cell>
    </van-cell-group>
  </div>
</template>

頂部圖片和課程信息敌呈,外加修改具體的樣式

// course-info/index.vue
...
<!-- 課程圖片 -->
<van-cell class="course-img">
  <img :src="course.courseImgUrl" alt="">
</van-cell>
<!-- 課程描述 -->
<van-cell class="course-desctription">
  <!-- 課程名稱 -->
  <h2 v-text="course.courseName"></h2>
  <!-- 課程概述 -->
  <p v-text="course.previewFirstField"></p>
  <!-- 課程銷售信息 -->
  <div class="course-saleInfo">
    <p class="course-price">
      <span class="discounts">¥{{ course.discounts }} </span>
      <span>¥{{ course.price }}</span>
    </p>
    <span class="tag">{{ course.sales }}人已購</span>
    <span class="tag">每周三、五更新</span>
  </div>
</van-cell>
...
<style lang="scss" scoped>
.van-cell {
  padding: 0;
}
.course-img {
  height: 280px;
}

.course-desctription {
  padding: 10px 20px;
  height: 150px;
}

.course-desctription h2 {
  padding: 0;
}

.course-saleInfo {
  display: flex;
}

.course-price {
  flex: 1;
  margin: 0;
}
.course-price .discounts {
  color: #ff7452;
  font-size: 24px;
  font-weight: 700;
}

.course-saleInfo .tag{
  line-height: 15px;
  background: #f8f9fa;
  border-radius: 2px;
  padding: 7px 8px;
  font-size: 12px;
  font-weight: 700;
  color: #666;
  margin-left: 10px;
}
</style>

主體選項卡

選項卡使用vant的Tab標(biāo)簽頁組件
設(shè)置到頁面中

<van-tabs v-model="active">
  <van-tab title="標(biāo)簽 1">內(nèi)容 1</van-tab>
  <van-tab title="標(biāo)簽 2">內(nèi)容 2</van-tab>
  <van-tab title="標(biāo)簽 3">內(nèi)容 3</van-tab>
  <van-tab title="標(biāo)簽 4">內(nèi)容 4</van-tab>
</van-tabs>

課程詳情

設(shè)置詳情部分?jǐn)?shù)據(jù)

<van-tab title="詳情">
       <!-- 課程詳情信息在后臺是通過富文本編輯器設(shè)置的 -->
      <!-- 內(nèi)容為html文本 -->
  <div v-html="course.courseDescription"></div>
</van-tab>

當(dāng)詳情內(nèi)容過于長的時候造寝,將選項卡部分固定磕洪,可以使用Tab組件的粘性定位功能(scrollspy表示滾動導(dǎo)航,美化效果拉滿)

// course-info/index.vue
<van-tabs sticky scrollspy>...</van-tabs>

章節(jié)列表處理

課程內(nèi)容要顯示課程的章節(jié)和課時信息

封裝接口

接口為獲取課程章節(jié):地址
封裝到course.js中

// course.js
...
// 獲取課程章節(jié)
export const getSectionAndLesson = params => {
  return request({
    method: 'GET',
    url: '/front/course/session/getSectionAndLesson',
    params
  })
}

封裝章節(jié)的組件

Vant沒有提供與需求相似的用于顯示章節(jié)和課時的組件诫龙,我們可以自行封裝一手
準(zhǔn)備組件文件析显,CourseSectionAndLesson用于單個章節(jié)與內(nèi)部課時展示

<template>
  <div class="course-section-and-lesson">章節(jié)列表</div>
</template>

<script>
export default {
  name: 'CourseSectionAndLesson',
  props: {
    sectionData: {
      type: Object,
      required: true
    }
  }
}
</script>

<style lang="scss" scoped>

</style>

引入該組件

// course-info/index.vue
...
<van-tab title="內(nèi)容">
  <course-section-and-lesson></course-section-and-lesson>
</van-tab>
...
<script>
import CourseSectionAndLesson from './components/CourseSectionAndLesson'
import { getCourseById, getSectionAndLesson } from '@/services/course'
...
components: {
  CourseSectionAndLesson
},
...
data () {
  return {
        ...
    // 章節(jié)信息
    sections: {}
  }
},
created () {
    ...
  this.loadSection()
},
...
methods: {
  async loadSection () {
    // 請求數(shù)據(jù)
    const { data } = await getSectionAndLesson({
      courseId: this.courseId
    })
    this.sections = data.content.courseSectionList
    console.log(data)
  },
...
</script>

遍歷sections,同時從父組件中傳遞數(shù)據(jù)給章節(jié)組件

<van-tab title="內(nèi)容">
  <course-section-and-lesson
    v-for="item in sections"
    :key="item.id"
    :section-data="item">
  </course-section-and-lesson>
</van-tab>

章節(jié)組件布局處理

<template>
  <div class="section-and-lesson">
    <!-- 章節(jié) -->
    <h2 class="section" v-text="sectionData.sectionName"></h2>
    <!-- 課時 -->
    <p
      v-for="item in sectionData.courseLessons"
      :key="item.id"
      class="lesson"
    >
      <!-- 課時標(biāo)題 -->
      <span v-text="item.theme"></span>
      <!-- 課時圖標(biāo)签赃,使用 Vant 的 icon 圖標(biāo)組件 -->
      <van-icon v-if="item.canPlay" name="play-circle" size="20" />
      <van-icon v-else name="lock" size="20" />
    </p>
  </div>
</template>

...

<style lang="scss" scoped>
.section-and-lesson {
  padding: 0 20px;
}
// 讓課時標(biāo)題與圖標(biāo)兩端顯示
.lesson {
  display: flex;
  justify-content: space-between;
}
</style>

底部支付功能

布局處理

整體采用vant的Tabbar組件谷异,也可自行設(shè)置元素進(jìn)行固定定位處理

// course-info/index.vue
<template>
  <div class="course-info">
    <!-- 如果已購,去除底部支付區(qū)域并設(shè)置主體內(nèi)容區(qū)域占滿屏幕 -->
    <van-cell-group :style="styleOptions">
      ...
    </van-cell-group>
    <!-- 底部支付功能 -->
    <van-tabbar v-if="!course.isBuy">
      <div class="price">
        <span v-text="course.discountsTag"></span>
        <span class="discounts">¥{{ course.discounts }}</span>
        <span>¥{{ course.price }}</span>
      </div>
      <van-button
        type="primary"
      >立即購買</van-button>
    </van-tabbar>
  </div>
</template>
...
data () {
  return {
    ...
    // 樣式信息
    styleOptions: {}
  }
},
...
async loadCourse () {
    ...
  if (data.content.isBuy) {
    this.styleOptions.bottom = 0
  }
}
...
<style lang="scss" scoped>
...
// 修改 discounts 選擇器范圍锦聊,讓頂部與底部均可使用
.discounts {
  color: #ff7452;
  font-size: 24px;
  font-weight: 700;
}
...

// 添加底部導(dǎo)航后設(shè)置
.van-cell-group {
  position: fixed;
  // 預(yù)留底部支付區(qū)域高度
  width: 100%;
  top: 0;
  bottom: 50px;
  overflow-y: auto;
}

// 調(diào)整內(nèi)部文字位置
.van-tabbar {
  line-height: 50px;
  // 設(shè)置 padding 后元素超出窗口
  padding: 0 20px;
  // 設(shè)置 box-sizing
  box-sizing: border-box;
  display: flex;
  // 內(nèi)部元素左右顯示
  justify-content: space-between;
  // 內(nèi)容居中
  align-items: center;
}

span {
  font-size: 14px;
}
// 尺寸調(diào)整
.van-button {
  width: 50%;
  height: 80%;
}
</style>

如果已經(jīng)購買了該課程歹嘹,就無需顯示這個功能了

  • 顯示隱藏控制
  • 主體內(nèi)容區(qū)域位置處理
// course-info/index.vue
<template>
  <div class="course-info">
    <!-- 如果已購,去除底部支付區(qū)域并設(shè)置主體內(nèi)容區(qū)域占滿屏幕 -->
    <van-cell-group :style="styleOptions">
      ...
    </van-cell-group>
    <!-- 底部支付功能 -->
    <van-tabbar v-if="!course.isBuy">
      ...
    </van-tabbar>
  </div>
</template>
...
data () {
  return {
    ...
    // 樣式信息
    styleOptions: {}
  }
},
...
async loadCourse () {
    ...
  if (data.content.isBuy) {
    this.styleOptions.bottom = 0
  }
}
...

視頻播放組件

組件準(zhǔn)備

當(dāng)點(diǎn)擊某個可播放的課時時孔庭,需要進(jìn)行視頻播放尺上,設(shè)置視頻組件用于播放視頻

  • 設(shè)置導(dǎo)航用于返回上一頁
// course-info/video.vue
<template>
  <div class="course-video">
    <!-- 導(dǎo)航 -->
    <van-nav-bar
      title="視頻"
      left-text="返回"
      @click-left="$router.go(-1)"
    />
  </div>
</template>

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

<style lang="scss" scoped></style>

設(shè)置路由:

// router/index.js
...
// 視頻頁
{
  path: '/lesson-video/:lessonId/',
  name: 'lesson-video',
  component: () => import(/* webpackChunkName: 'lesson-video' */'@/views/course-info/video'),
  props: true
},
...

點(diǎn)擊課時時,如果可以播放史飞,那么就跳轉(zhuǎn)該視頻頁尖昏,并傳遞ID課時

// CourseSection.vue
...
<p
  ...
  @click="handleClick(item)"
>
...
<script>
  methods: {
    handleClick (lessonInfo) {
      if (lessonInfo.canPlay) {
        this.$router.push({
          name: 'lesson-video',
          params: {
            lessonId: lessonInfo.id
          }
        })
      }
    }
  }
...

video.vue接收lessonId用于請求視頻數(shù)據(jù)

// course-info/video.vue
...
    props: {
    lessonId: {
      type: [String, Number],
      required: true
    }
  },
...

接口封裝

需要使用以下的接口

  • 根據(jù)fileId獲取阿里云對應(yīng)的視頻播放信息:接口
// course.js
...
// 根據(jù)fileId獲取阿里云對應(yīng)的視頻播放信息
export const getVideoInfo = params => {
  return request({
    method: 'GET',
    url: '/front/course/media/videoPlayInfo',
    params
  })
}

引入,請求

// video.vue
...
import { getVideoInfo } from '@/services/course'
...
  created () {
    this.loadVideo()
  },
  methods: {
    async loadVideo () {
      const { data } = await getVideoInfo({
        lessonId: this.lessonId
      })
      console.log(data)
    }
  }

阿里云視頻點(diǎn)播

播放需要使用阿里云的視頻播放功能

在public/index.html中引入文件:

  • css文件:
<link rel="stylesheet"  />
  • js文件:
<script src="https://g.alicdn.com/de/prismplayer/2.9.3/aliplayer-h5-min.js"></script>

可使用在線配置獲取創(chuàng)建實(shí)例代碼

  • 選擇playauth播放方式即可
    具體的代碼
<template>
  <div class="course-video">
    ...
    <!-- 設(shè)置視頻容器 -->
    <div id="video-container"></div>
  </div>
</template>

<script>
// 引入接口构资,請求視頻播放需要的 vid 與 playAuth
import { getVideoInfo } from '@/services/course'
export default {
  ...
  created () {
    this.loadVideo()
  },
  methods: {
    async loadVideo () {
      const { data } = await getVideoInfo({
        lessonId: this.lessonId
      })
      // 初始化播放器
      const player = new window.Aliplayer({
        // 視頻容器 ID
        id: 'video-container',
        // 視頻 ID
        vid: data.content.fileId,
        // 播放憑證
        playauth: data.content.playAuth,
        qualitySort: 'asc',
        format: 'mp4',
        mediaType: 'video',
        width: '100%',
        // 高度調(diào)整
        height: '100%',
        autoplay: true,
        isLive: false,
        rePlay: false,
        playsinline: true,
        preload: true,
        controlBarVisibility: 'hover',
        useH5Prism: true
      }, function (player) {
        console.log('The player is created')
      })
      console.log(player)
    }
  }
}
</script>

<style lang="scss" scoped>
.course-video {
  width: 100%;
  height: 210px;
}
#video-container {
  width: 100%;
  height: auto;
}
</style>

小知識:手機(jī)和電腦鏈接到同一個無線網(wǎng)絡(luò)下抽诉,可以使用手機(jī)訪問IP地址:8080端口訪問項目,可以調(diào)試項目
完成

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吐绵,一起剝皮案震驚了整個濱河市迹淌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌己单,老刑警劉巖唉窃,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異纹笼,居然都是意外死亡纹份,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔓涧,“玉大人件已,你說我怎么就攤上這事≡” “怎么了篷扩?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長茉盏。 經(jīng)常有香客問我鉴未,道長,這世上最難降的妖魔是什么鸠姨? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任铜秆,我火速辦了婚禮,結(jié)果婚禮上享怀,老公的妹妹穿的比我還像新娘羽峰。我一直安慰自己,他們只是感情好添瓷,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布梅屉。 她就那樣靜靜地躺著,像睡著了一般鳞贷。 火紅的嫁衣襯著肌膚如雪坯汤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天搀愧,我揣著相機(jī)與錄音惰聂,去河邊找鬼。 笑死咱筛,一個胖子當(dāng)著我的面吹牛搓幌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播迅箩,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼溉愁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饲趋?” 一聲冷哼從身側(cè)響起拐揭,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奕塑,沒想到半個月后堂污,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡龄砰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年盟猖,在試婚紗的時候發(fā)現(xiàn)自己被綠了讨衣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡扒披,死狀恐怖值依,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碟案,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布颇蜡,位于F島的核電站价说,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏风秤。R本人自食惡果不足惜鳖目,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缤弦。 院中可真熱鬧领迈,春花似錦、人聲如沸碍沐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽累提。三九已至尘喝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間斋陪,已是汗流浹背朽褪。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留无虚,地道東北人缔赠。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像友题,于是被迫代替她去往敵國和親嗤堰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 01-課程頁面靜態(tài)效果整合 一咆爽、列表頁面 創(chuàng)建 pages/course/index.vue 二梁棠、詳情頁面 創(chuàng)建 ...
    刊ing閱讀 1,060評論 0 0
  • Course組件為選課頁面,分為上中下三個部分斗埂,頂部為顯示logo的導(dǎo)航區(qū)域符糊,中間為課程選擇區(qū)域(輪播+課程列表)...
    amanohina閱讀 501評論 0 1
  • 導(dǎo)讀:從JDK 5.0開始 J2EE 改名為 Java EE。 Java EE被企業(yè)廣泛使用呛凶,必然有其可取之處男娄,甚...
    堯淳閱讀 648評論 0 3
  • 登錄功能 布局處理 頁面分為上下兩個部分,頂部為導(dǎo)航,底部為登錄表單首先我們創(chuàng)建登錄組件模闲,然后配置路由 配置路由建瘫,...
    amanohina閱讀 594評論 0 1
  • 夜鶯2517閱讀 127,712評論 1 9