Vue3.0入門 + Vant3.0移動端實踐(二)輪播圖模組封裝及首頁完善
技術標籤:vue.js
接著上一篇的來,上一篇介紹了環境搭建及做好了底部的導航欄模組,接下來繼續完善首頁。
先來張最終效果圖:
記錄下之前遇到的問題,Vue中img影象src變成"[object Module]"無法正確載入的問題。
我在vue專案的js程式碼中,使用了"imgUrl"=require('../asserts/image.png')這種形式。
網上查了很多資料,說是因為file-loader預設採用ES模組語法,即import '../image.png'
;然而Vue生成的是CommonJS模組語法,即require('../image.png')
但是我找了下專案中的各個檔案,沒找到在哪能改esModule: false的選項,於是暫時作罷。
最終我找到的折中的辦法,本地圖片和css資源都放在public目錄下,這樣就可以了。
本地的css檔案在index.html檔案里加載,如:
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="<%= BASE_URL %>css/font_nbicon.css">
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="stylesheet" href="<%= BASE_URL %>css/font_nbicon.css"> <title>物聯網報警系統</title> </head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
以下是輪播圖模組封裝,本地的圖片放在public目錄裡,使用時直接引入路徑即可:
在components目錄下新建Swiper.vue元件:
<template>
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="#1baeae">
<van-swipe-item v-for="(item, index) in list" :key="index">
<img :src="item.imgUrl" alt="暫無圖片">
</van-swipe-item>
</van-swipe>
</template>
<script>
export default {
props: {
list: Array
},
methods: {
}
}
</script>
<style lang='less' scoped>
.my-swipe {
display: flex;
flex-shrink: 0;
flex-wrap: wrap;
width: 100%;
padding-top: 45px;
img {
width: 100%;
height: 100%;
}
}
</style>
style調整介面的less寫法,
display: flex;含義為使用flex佈局。
padding-top: 45px;為輪播圖最上面的titile留出45px的位置。
js的props屬性裡增加了個list,型別為Array,作為子元件接收屬性。
接下來看看首頁Home.vue裡如何用:
import swiper from '@/components/Swiper'
先import引入進來,export default的components裡註冊元件。
template模板標籤裡這麼使用:<swiper :list="swiperList"></swiper>
注意setup(),ref,torefs,reactive都為vue3的新用法,setup是Vue3 的一大特性函式 。
setup函式是處於 生命週期函式 beforeCreate 和 Created 兩個鉤子函式之間的函式。
setup函式是 Composition API(組合API)的入口。
在setup函式中定義的變數和方法最後都是需要 return 出去的 不然無法再模板中使用。
在執行 setup函式的時候,還沒有執行 Created 生命週期方法,所以在 setup 函式中,無法使用 data 和 methods 的變數和方法。
setup函式只能是同步的不能是非同步的。
舊的Vue2.0 Options API 和 新的Vue3.0 Composition API 區別
Vue2.0 Options API 約定:
我們需要在 props 裡面設定接收引數
我們需要在 data 裡面設定變數
我們需要在 computed 裡面設定計算屬性
我們需要在 watch 裡面設定監聽屬性
我們需要在 methods 裡面設定事件方法
你會發現 Options APi 都約定了我們該在哪個位置做什麼事,這反倒在一定程度上也強制我們進行了程式碼分割。
現在用 Composition API,不再這麼約定了,於是乎,程式碼組織非常靈活,我們的控制程式碼寫在 setup 裡面即可。
setup函式提供了兩個引數 props和context,重要的是在setup函式裡沒有了this,在vue3.0中,訪問他們變成以下形式: this.xxx=》context.xxx
我們沒有了 this 上下文,沒有了 Options API 的強制程式碼分離,Composition API 給了我們更加廣闊的天地。
接下來說下ref和reactive。vue3在9月18號晚上釋出了,在vue3中對響應式資料的宣告官方給出了ref()和reactive()這兩種方式。
雙向資料繫結,vue一共提供了兩種資料響應式監聽,有點React Hooks的味道。ref 函式傳入一個值作為引數,返回一個基於該值的響應式Ref物件,該物件中的值一旦被改變和訪問,都會被跟蹤到,就像我們改寫後的示例程式碼一樣,通過修改 count.value 的值,可以觸發模板的重新渲染,顯示最新的值。
其實,除了 ref 函式,Vue3.0中還提供了另外一個可以建立響應式物件的函式,那就是 reactive 函式。下面就來說說為什麼要提供兩種API
ref寫法簡單,但也有弊端,經過嘗試發現他只能監聽一些如數字、字串、布林之類的簡單資料。
ref修改資料需要使用這樣count.value=xxx的形式,而reactive只需要state.reactiveField=值這樣來使用。
reactive在return時候需要toRefs來轉換成響應式物件。
toRefs函式能將reactive建立的響應式物件,轉化成為普通的物件,並且這個物件上的每個節點,都是ref()型別的響應式資料。
在Vue中使用可以直接使用ref (template中),Vue會自動新增.value。在Js中使用ref需要.value。
setup函式必須有返回值,必須返回個物件。
setup函式有一個props引數,用於接收props,也就是定義在元件上的屬性(同vue2),但是接收的props必須先在props屬性中定義,否則是不會被接收到。
vue2的所有生命週期寫法與vue3相容,而在vue3中,生命週期添加了on字首,需要匯入並寫在setup()函式中。
<template>
<div>
<header class="home-header wrap" :class="{'active' : headerScroll}">
<div class="header-search">
<span class="app-name">物聯網報警系統</span>
</div>
</header>
<nav-bar />
<swiper :list="swiperList"></swiper>
<div class="category-list">
<div v-for="item in categoryList" v-bind:key="item.categoryId" @click="tips">
<img :src="item.imgUrl">
<span>{{item.name}}</span>
</div>
</div>
</div>
</template>
<script>
import navBar from '@/components/NavBar'
import swiper from '@/components/Swiper'
import { getHome } from '@/service/home'
import { Toast } from 'vant'
import { reactive, onMounted , toRefs} from 'vue'
export default {
name: 'home',
components: {
navBar,
swiper
},
setup() {
const state = reactive({
swiperList: [] ,// 輪播圖列表
categoryList: [
{
name: '檢視裝置',
imgUrl: '/image/kj1.png',
categoryId: 100001
}, {
name: '使用者資訊',
imgUrl: '/image/kj2.png',
categoryId: 100002
}, {
name: '充值中心',
imgUrl: '/image/kj3.png',
categoryId: 100003
},{
name: '功能預留',
imgUrl: '/image/kj4.png',
categoryId: 100004
}, {
name: '全部',
imgUrl: '/image/kj5.png',
categoryId: 100005
}
],
})
onMounted(async () => {
Toast.loading({
message: '載入中...',
forbidClick: true
});
const { data } = await getHome()
console.log(data)
state.swiperList = data.swiperLists
Toast.clear()
})
const tips = () => {
Toast('敬請期待');
}
return {
...toRefs(state),
tips
}
}
}
</script>
<style lang="less" scoped >
@import '../common/style/mixin';
.home-header {
position: fixed;
left: 0;
top: 0;
.wh(100%, 45px);
.fj(center);
line-height: 45px;
padding: 0 15px;
.boxSizing();
font-size: 15px;
color: #fff;
background: #39A2FD;
z-index: 10000;
.app-name {
padding: 0 5px;
color: #ffffff;
font-size: 18px;
}
}
.category-list {
display: flex;
flex-shrink: 0;
flex-wrap: wrap;
width: 100%;
padding-bottom: 13px;
div {
display: flex;
flex-direction: column;
width: 20%;
text-align: center;
img {
.wh(36px, 36px);
margin: 13px auto 8px auto;
}
}
}
</style>
至此,首頁基本設計完成,接下來會繼續介紹個人中心頁面的詳細設計過程。先來張截圖吧: