【筆記】實戰mpvue2.0多端小程序框架——書架模塊


一、圖書列表頁面開發 + 列表 API 對接

新建src\pages\list\list.vue:

<template>
  <div>
    123
  </div>
</template>

<script>

export default {
  components: {},
  data() {
    return {
    }
  },
  mounted() {
  },
  methods: {
  }
}
</script>

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

新建src\pages\list\main.js:

import Vue from 'vue'
import App from './list'

const app = new Vue(App)
app.$mount()

修改src\components\search\SearchList.vue的showList方法來跳轉到圖書列表頁:

    showList(text, key) {
      console.log(text, key)
      this.$router.push({
        path: '/pages/list/main',
        query: {
          text, key, title: text
        }
      })
    },

在src\api\index.js中新建一個接口函數searchList,用來獲取圖書列表:

export function searchList(params) {
  return get(`${API_URL}/book/shelf/search-list`, params)
}

修改src\pages\list\list.vue:

<template>
  <div>
    <SearchTable :data="data"/>
  </div>
</template>

<script>
import SearchTable from '../../components/search/SearchTable'
import {searchList} from '../../api'

export default {
  components: {SearchTable},
  data() {
    return {
      data: []
    }
  },
  mounted() {
    this.getSearchList()
  },
  methods: {
    getSearchList() {
      const { key, text } = this.$route.query
      const params = {}
      if (key && text) {
        params[key] = text
      }
      searchList(params).then(res => {
        this.data = res.data.data
      })
    }
  }
}
</script>

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

預覽:
搜索頁點擊(出版社/作者/分類)標籤觸發
在這裏插入圖片描述

二、圖書列表標題動態切換+圖書詳情頁跳轉

在src\api\wechat.js中新建一個接口函數setNavigationBarTitle,用來動態設置標題:

export function setNavigationBarTitle(title) {
  mpvue.setNavigationBarTitle({ title })
}

接下來在mounted中調用setNavigationBarTitle:

  mounted() {
    this.getSearchList()
    const { title } = this.$route.query
    setNavigationBarTitle(title)
  },

由於SearchTable點擊是一定會跳轉到圖書詳情頁的,因此將跳轉直接加到SearchTable中,其他事件內容依舊通過$emit交給調用者處理:
src\components\search\SearchTable.vue

    onClick(book) {
      this.$router.push({
        path: '/pages/detail/main',
        query: {
          fileName: book.fileName
        }
      })
      this.$emit('onClick', book)
    }

刪掉src\components\search\SearchList.vue中關於onBookClick的內容和調用
預覽:
在這裏插入圖片描述

三、圖書列表觸底自動刷新功能開發

data中新增page: 1
修改getSearchList方法:

    getSearchList() {
      const { key, text } = this.$route.query
      const params = {}
      if (key && text) {
        params[key] = text
      }
      params.page = this.page
      searchList(params).then(res => {
        const { data } = res.data
        if (data.length > 0) {
          this.data.push(...data)
        } else {
          showToast('沒有更多數據了')
        }
      })
    }

新增周期函數:

  onReachBottom() {
    this.page++
    this.getSearchList()
  },

在mounted中新增一句:this.page = 1防止打開新list頁面時舊list頁面未銷燬時導致的page未初始化問題

這樣就實現了觸底刷新

四、分類列表頁面開發 + 分類 API 對接

新建src\pages\categoryList\main.json:

{
  "navigationBarTitleText": "分類列表"
}

新建src\pages\categoryList\main.js:

import Vue from 'vue'
import App from './categoryList'

const app = new Vue(App)
app.$mount()

新建src\pages\categoryList\categoryList.vue:

<template>
  <div>
  </div>
</template>

<script>
export default {
}
</script>

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

在首頁中新加跳轉到categoryList頁面,即爲onCategoryMoreClick完善內容:

    onCategoryMoreClick() {
      this.$router.push({
        path: '/pages/categoryList/main'
      })
    },

在src\api\index.js中新建一個接口函數categoryList,用來拿到所有分類列表:

export function categoryList() {
  return get(`${API_URL}/book/category/list/v2`)
}

完成分類列表頁面src\pages\categoryList\categoryList.vue:

<template>
  <div>
    <HomeBook
      title="圖書分類"
      :row="category.length / 2"
      :col="2"
      :data="category"
      mode="category"
      :show-btn="false"
      :show-title="false"
    />
  </div>
</template>

<script>
import HomeBook from '../../components/home/HomeBook'
import {categoryList} from '../../api'
export default {
  components: { HomeBook },
  data() {
    return {
      category: []
    }
  },
  mounted() {
    categoryList().then(res => {
      this.category = res.data.data
    })
  }
}
</script>

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

預覽
在這裏插入圖片描述

五、分類列表跳轉圖書列表功能開發

修改src\pages\index\index.vue中圖書分類HomeBook的事件監聽屬性onBookClick爲:@onBookClick="onCategoryClick"

新增onCategoryClick方法:

    onCategoryClick(category) {
      this.$router.push({
        path: '/pages/list/main',
        query: {
          key: 'categoryId',
          text: category.category,
          title: category.categoryText
        }
      })
    }

同樣也爲src\pages\categoryList\categoryList.vue中的HomeBook新增@onBookClick="onCategoryClick"

    onCategoryClick(category) {
      this.$router.push({
        path: '/pages/list/main',
        query: {
          key: 'categoryId',
          text: category.category,
          title: category.categoryText
        }
      })
    }

六、閱讀器頁面開發

1.學習重點

  • webview 組件的使用(查看官方文檔
  • 閱讀器模塊的集成方法

2.閱讀器組件

組件名稱 屬性 參數 用途 默認值
read data fileName 圖書的唯一標識 -
opf 圖書opf文件地址 -
navigation 圖書目錄地址 -

3.動手操作

新建src\pages\read\main.json:

{
  "navigationBarTitleText": "閱讀器"
}

新建src\pages\read\main.js:

import Vue from 'vue'
import App from './read'

const app = new Vue(App)
app.$mount()

新建src\pages\read\read.vue:

<template>
  <web-view :src="url"></web-view>
</template>

<script>
export default {
  data() {
    return {
      url: ''
    }
  },
  mounted() {
    const { query } = this.$route
    let _url = 'https://www.youbaobao.xyz/book/#/ebook'
    if (query.fileName) {
      _url = `${_url}/${query.fileName}`
      if (query.opf) {
        _url = `${_url}?opf=${query.opf}`
      }
      if (query.navigation && query.opf) {
        _url = `${_url}&navigation=${query.navigation}`
      } else if (query.navigation) {
        _url = `${_url}?navigation=${query.navigation}`
      }
      this.url = _url
    }
  }
}
</script>

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

完善src\pages\detail\detail.vue頁面的readBook方法:

    readBook(href) {
      const query = {
        fileName: this.book.fileName,
        opf: this.book.opf
      }
      if (href) {
        // 找到標記位置
        const index = href.toString().indexOf('/')
        if (index >= 0) {
          // 標記存在則做截斷(從標記的下一個位置開始讀取)
          query.navigation = href.slice(index + 1)
        } else {
          query.navigation = href
        }
      }
      if (this.book && this.book.fileName) {
        this.$router.push({
          path: '/pages/read/main',
          query
        })
      }
    },

預覽:
在這裏插入圖片描述
這樣就可以閱讀圖書了

七、書架頁面開發

1.學習重點

  • API對接:
    • 加入時間API
    • 書架列表API

2.書架視覺稿

http://www.youbaobao.xyz/mpvue-design/preview/#artboard6

3.用戶信息面板

組件名稱 屬性 參數 用途 默認值
ShelfUserInfo props num 書架圖書數量 0
readDay 加入天數 0
userInfo 用戶信息 {}

4.書架列表組件

組件名稱 屬性 參數 用途 默認值
ShelfList props shelfList 書架列表 []
methods gotoHome 訪問首頁 -
gotoBookDetail 訪問圖書詳情 -

5.動手操作

新建src\pages\shelf\main.json:

{
  "navigationBarTitleText": "書架"
}

新建src\pages\shelf\main.js:

import Vue from 'vue'
import App from './shelf'

const app = new Vue(App)
app.$mount()

新建src\pages\shelf\shelf.vue:

<template>
  <div></div>
</template>

<script>
export default {
  data() {
    return {
    }
  },
  mounted() {
    }
  }
}
</script>

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

修改src\components\home\HomeCard.vue的gotoShelf方法爲:

    gotoShelf() {
      this.$router.push('/pages/shelf/main')
    },

八、書架用戶面板組件開發

新建組件:src\components\shelf\ShelfUserInfo.vue:

<template>
  <div class="user-info-wrapper">
    <div class="user-info">
      <div class="user-nick-name">{{userInfo.nickName}}</div>
      <div class="user-read-time">您已經加入小慕讀書{{readDay}}天</div>
      <div class="user-avatar-wrapper">
        <img class="user-avatar" :src="userInfo.avatarUrl" mode="widthFix">
      </div>
    </div>
    <div class="user-extra">
      <div class="user-extra-text">您的書架中共有 {{num}} 本好書</div>
    </div>
  </div>
</template>

<script>
  export default {
    props: {
      num: Number,
      readDay: Number,
      userInfo: Object
    }
  }
</script>

<style lang="scss" scoped>
  .user-info-wrapper {
    margin: 15px 25px;
    background: #F8F9FB;
    border-radius: 12px;
    padding: 15px 20px;
    border: 1px solid #E0E1E2;

    .user-info {
      position: relative;
      height: 60px;
      border-bottom: 1px solid #E9E9E9;

      .user-nick-name {
        font-size: 17px;
        font-weight: 500;
        color: #333;
      }

      .user-read-time {
        font-size: 12px;
        color: #868686;
      }

      .user-avatar-wrapper {
        position: absolute;
        right: 0;
        top: 0;

        .user-avatar {
          width: 40px;
          border-radius: 50%;
        }
      }
    }

    .user-extra {
      margin-top: 15px;

      .user-extra-text {
        font-size: 12px;
        color: #666;
        font-weight: 500;
      }
    }
  }
</style>

在src\api\index.js中新增接口調用,用來獲取用戶註冊天數:

export function userDay(params) {
  return get(`${API_URL}/user/day`, params)
}

修改src\pages\shelf\shelf.vue爲:

<template>
  <div>
    <ShelfUserInfo
      :user-info="userInfo"
      :read-day="readDay"
      :num="shelfList.length"
    />
  </div>
</template>

<script>
import ShelfUserInfo from '../../components/shelf/ShelfUserInfo'
import {getStorageSync} from '../../api/wechat'
import {bookShelf, userDay} from '../../api'
export default {
  components: {ShelfUserInfo},
  data() {
    return {
      userInfo: {},
      readDay: 0,
      shelfList: []
    }
  },
  mounted() {
    this.userInfo = getStorageSync('userInfo')
    const openId = getStorageSync('openId')
    userDay({ openId }).then(res => {
      this.readDay = res.data.data.day
    })
    bookShelf({ openId }).then(res => {
      this.shelfList = res.data.data
    })
  }
}
</script>

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

這裏已經修改bookIsInShelf接口名稱爲bookShelf

預覽:
在這裏插入圖片描述

九、書架列表組件開發

新建src\components\shelf\ ShelfList.vue:

<template>
  <div class="shelf-list-wrapper">
    <div class="shelf-list-inner">
      <div
        class="shelf-book"
        v-for="book in shelfList"
        :key="book.fileName"
      >
        <div
          class="shelf-book-cover"
          v-if="book && book.cover"
          @click="() => gotoBookDetail(book)"
        >
          <ImageView :src="book.cover"></ImageView>
        </div>
        <div class="shelf-book-title" v-if="book && book.title">{{book.title}}</div>
        <div class="shelf-book-add" v-if="!book.title" @click="gotoHome">
          <div class="shelf-book-add-wrapper">
            <div class="shelf-book-add-x"></div>
            <div class="shelf-book-add-y"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  import ImageView from '../base/ImageView'
  export default {
    components: { ImageView },
    props: {
      shelfList: Array
    },
    methods: {
      gotoHome() {
        this.$router.push('/pages/index/main')
      },
      gotoBookDetail(book) {
        this.$router.push({ path: '/pages/detail/main', query: { fileName: book.fileName } })
      }
    }
  }
</script>

<style lang="scss" scoped>
  .shelf-list-wrapper {
    padding: 0 12.5px 20px 12.5px;

    .shelf-list-inner {
      display: flex;
      flex-flow: row wrap;

      .shelf-book {
        flex: 0 0 33.33%;
        width: 33.33%;
        padding: 20px 12.5px 0 12.5px;
        box-sizing: border-box;

        .shelf-book-cover {
          width: 100%;
          height: 130px;
        }

        .shelf-book-title {
          width: 100%;
          font-size: 12px;
          color: #333;
          overflow: hidden;
          text-overflow: clip;
          line-height: 14px;
          max-height: 28px;
          margin-top: 10px;
        }

        .shelf-book-add {
          width: 100%;
          height: 130px;
          border: 1px solid #CBCBCB;
          box-sizing: border-box;
          display: flex;
          align-items: center;
          justify-content: center;

          .shelf-book-add-wrapper {
            position: relative;
            width: 30px;
            height: 30px;

            .shelf-book-add-x {
              position: absolute;
              top: 50%;
              width: 30px;
              height: 2px;
              margin-top: -1px;
              background: #CACACA;
            }

            .shelf-book-add-y {
              position: absolute;
              left: 50%;
              width: 2px;
              height: 30px;
              background: #CACACA;
            }
          }
        }
      }
    }
  }
</style>

直接在src\pages\shelf\shelf.vue中調用組件:

    <ShelfList :shelfList="shelfList" />

修改mounted爲onShow並給shelfList push一個空對象:

  onShow() {
    this.userInfo = getStorageSync('userInfo')
    const openId = getStorageSync('openId')
    userDay({ openId }).then(res => {
      this.readDay = res.data.data.day
    })
    bookShelf({ openId }).then(res => {
      this.shelfList = res.data.data
      this.shelfList.push({})
    })
  }

預覽:
在這裏插入圖片描述

mounted在頁面加載時只調用一次,而onShow是小程序頁面的生命週期函數,在每次頁面獲得焦點時都會調用,包括首次加載和再次返回

此處有大坑:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章