黑马的视频学习
首页
组件封装
只有一个页面需要使用
以首页导航栏示例
/index/index.vue
1
2
3
4
5
6
7
8
9
10
11
12
<script setup lang="ts">
import CustomNavbar from './componets/CustomNavbar.vue';
</script>
<template>
<!-- 自定义导航栏 -->
<CustomNavbar />
</template>
<style lang="scss">
//
</style>
/index/components/CustomNavbar.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
< script setup lang = "ts" >
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni . getSystemInfoSync ()
</ script >
< template >
< view class = "navbar" : style = "{ paddingTop: safeAreaInsets?.top + 10 + 'px' }" >
<!-- logo文字 -->
< view class = "logo" >
< image class = "logo-image" src = "@/static/images/logo.png" ></ image >
< text class = "logo-text" > 新鲜 · 亲民 · 快捷 </ text >
</ view >
<!-- 搜索条 -->
< view class = "search" >
< text class = "icon-search" > 搜索商品 </ text >
< text class = "icon-scan" ></ text >
</ view >
</ view >
</ template >
< style lang = "scss" >
/* 自定义导航条 */
. navbar {
background - image : url ( @ / static / images / navigator_bg . png );
background - size : cover ;
position : relative ;
display : flex ;
flex - direction : column ;
padding - top : 20 px ;
. logo {
display : flex ;
align - items : center ;
height : 64 rpx ;
padding - left : 30 rpx ;
. logo - image {
width : 166 rpx ;
height : 39 rpx ;
}
. logo - text {
flex : 1 ;
line - height : 28 rpx ;
color : #fff;
margin : 2 rpx 0 0 20 rpx ;
padding - left : 20 rpx ;
border - left : 1 rpx solid #fff;
font - size : 26 rpx ;
}
}
. search {
display : flex ;
align - items : center ;
justify - content : space - between ;
padding : 0 10 rpx 0 26 rpx ;
height : 64 rpx ;
margin : 16 rpx 20 rpx ;
color : #fff;
font - size : 28 rpx ;
border - radius : 32 rpx ;
background - color : rgba ( 255 , 255 , 255 , 0.5 );
}
. icon - search {
& :: before {
margin - right : 10 rpx ;
}
}
. icon - scan {
font - size : 30 rpx ;
padding : 15 rpx ;
}
}
</ style >
关键代码
1
2
3
4
5
6
7
8
< script setup lang = "ts" >
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni . getSystemInfoSync ()
</ script >
< template >
< view class = "navbar" : style = "{ paddingTop: safeAreaInsets?.top + 10 + 'px' }" >
...
需要多个页面使用【全局组件】
轮播图为例
/src/components/XtxSwiper.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
< script setup lang = "ts" >
import { ref } from 'vue'
const activeIndex = ref ( 0 )
</ script >
< template >
< view class = "carousel" >
< swiper : circular = "true" : autoplay = "false" : interval = "3000" >
< swiper - item >
< navigator url = "/pages/index/index" hover - class = "none" class = "navigator" >
< image
mode = "aspectFill"
class = "image"
src = "https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/slider_1.jpg"
></ image >
</ navigator >
</ swiper - item >
< swiper - item >
< navigator url = "/pages/index/index" hover - class = "none" class = "navigator" >
< image
mode = "aspectFill"
class = "image"
src = "https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/slider_2.jpg"
></ image >
</ navigator >
</ swiper - item >
< swiper - item >
< navigator url = "/pages/index/index" hover - class = "none" class = "navigator" >
< image
mode = "aspectFill"
class = "image"
src = "https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/slider_3.jpg"
></ image >
</ navigator >
</ swiper - item >
</ swiper >
<!-- 指示点 -->
< view class = "indicator" >
< text
v - for = "(item, index) in 3"
: key = "item"
class = "dot"
: class = "{ active: index === activeIndex }"
></ text >
</ view >
</ view >
</ template >
< style lang = "scss" >
: host {
display : block ;
height : 280 rpx ;
}
/* 轮播图 */
. carousel {
height : 100 % ;
position : relative ;
overflow : hidden ;
transform : translateY ( 0 );
background - color : #efefef;
. indicator {
position : absolute ;
left : 0 ;
right : 0 ;
bottom : 16 rpx ;
display : flex ;
justify - content : center ;
. dot {
width : 30 rpx ;
height : 6 rpx ;
margin : 0 8 rpx ;
border - radius : 6 rpx ;
background - color : rgba ( 255 , 255 , 255 , 0.4 );
}
. active {
background - color : #fff;
}
}
. navigator ,
. image {
width : 100 % ;
height : 100 % ;
}
}
</ style >
关键代码
自动导入设置【和uni-app自动导入设置类似】
使用正则匹配方法
pages.json
1
2
3
4
5
6
7
8
9
10
11
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
// 以Xtx 开头的组件,在components文件夹中查找引入
"^Xtx(.*)": "@/components/Xtx$1.vue"
}
},
"pages":
...
对全局组件进行类型声明
模板代码
1
2
3
4
5
declare module '@vue/runtime-core' {
export interface GlobalComponents {
}
}
代码使用
1
2
3
4
5
6
7
import XtxSwiper from "./XtxSwiper.vue" ;
declare module '@vue/runtime-core' {
export interface GlobalComponents {
XtxSwiper : typeof XtxSwiper
}
}
轮播图指示点高光跟随
原代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
< script setup lang = "ts" >
import { ref } from 'vue'
const activeIndex = ref ( 0 )
</ script >
< template >
...
<!-- 指示点 -->
< view class = "indicator" >
< text
v - for = "(item, index) in 3"
: key = "item"
class = "dot"
: class = "{ active: index === activeIndex }"
></ text >
</ view >
...
< \template >
在swiper上绑定change事件
1
<swiper :circular="true" :autoplay="false" :interval="3000" @change="onChange">
获取事件数据,并发现detail里面的current随着变化滑动而变化数字。因此作为滑动指示点的高亮显示记号。
1
2
3
4
5
6
7
8
9
10
11
< script setup lang = "ts" >
import { ref } from 'vue'
const activeIndex = ref ( 0 )
// 当 swiper 下标发生变化时触发
const onChange : UniHelper . SwiperOnChange = ( ev ) => {
// 不用?用 ! ,是非空断言,主观上排除空的情况
activeIndex . value = ev . detail !. current
}
</ script >
ev的类型使用了UniHelper.SwiperOnChange
各模块加入到主页并渲染等步骤
在 /index/components 中保存对应模块的封装文件(.vue)
查看对应组件的AIP文档相关信息,在 /service/home.ts 中封装组件AIP
1
2
3
4
5
6
7
8
9
10
11
/**
* 首页 - 热门推荐 - 小程序
* GET
* / home / hot / mutli
*/
export const getHomeHotAPI = () => {
return http ({
method : 'GET' ,
url : '/home/hot/mutli'
})
}
在 index.vue 中的 template 标签里调用组件。并获取数据以及载入页面。
1
2
3
4
5
6
7
8
9
10
// 获取热门推荐数据
const getHomeHotData = async () => {
const res = await getHomeHotAPI ()
}
...
onLoad (() => {
getHomeBannerData ()
getHomeCategoryAPIData ()
getHomeHotData ()
})
在 /types/home.d.ts 中定义数据类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/** 首页 - 热门推荐数据类型 */
export type HotItem = {
/** 说明 */
alt : string
/** id */
id : string
/** 图片集合 [ 图片路径 ] */
pictures : string []
/** 跳转地址 */
target : string
/** 标题 */
title : string
/** 推荐类型 */
type : string
}
此数据类型即为封装API中http的类型,但是http的内容是数组
1
2
3
4
5
6
7
8
9
10
11
/**
* 首页 - 热门推荐 - 小程序
* GET
* / home / hot / mutli
*/
export const getHomeHotAPI = () => {
return http < HotItem > ({
method : 'GET' ,
url : '/home/hot/mutli'
})
}
在 index.vue 中得到具体的数据并把数据传到组件中
1
2
3
4
5
6
7
8
9
10
11
12
13
< script >
// 获取热门推荐数据
const hotList = ref < HotItem [] > ([])
const getHomeHotData = async () => {
const res = await getHomeHotAPI ()
hotList = res . result
}
</ script >
...
< template >
<!-- 热门推荐 -->
< HotPanel : list = "hotList" />
</ template >
在组件的vue文件中定义props接收数据
1
2
3
4
5
6
7
<script setup lang="ts">
...
// 定义props接收数据,一般是列表
defineProps<{
list: HotItem[]
}>()
</script>
把组件中静态数据换成当前调用的数据(一般通过v-for循环)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<!-- 推荐专区 -->
<view class="panel hot">
<view class="item" v-for="item in list" :key="item.id">
<view class="title">
<text class="title-text">{{ item.title }}</text>
<text class="title-desc">{{ item.alt }}</text>
</view>
<navigator hover-class="none" url="/pages/hot/hot" class="cards">
<image v-for="src in item.pictures" :key="src" class="image" mode="aspectFit" :src="src">
</image>
</navigator>
</view>
</view>
</template>
自动导入公用组件
可以不用import导入就能使用,但是需要定义类型在 /types/conponents.d.ts
1
2
3
4
5
6
7
8
9
import XtxSwiper from "@/components/XtxSwiper.vue" ;
import XtxGuess from "@/components/XtxGuess.vue" ;
declare module '@vue/runtime-core' {
export interface GlobalComponents {
XtxSwiper : typeof XtxSwiper
XtxGuess : typeof XtxGuess
}
}
定义自动导入,在 /src/page.json
1
2
3
4
5
6
7
8
9
10
11
12
{
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
// 以Xtx 开头的组件,在components文件夹中查找引入
"^Xtx(.*)": "@/components/Xtx$1.vue"
}
},
"pages": [...]
}
页面滚动设置
flexBox使用
scoll-view使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<!-- 自定义导航栏 -->
<CustomNavbar />
<scroll-view class="scroll-view" scroll-y>
<!-- 自定义轮播图 -->
<XtxSwiper :list="bannerList" />
<!-- 分类面板 -->
<CategoryPanel :list="categoryList" />
<!-- 热门推荐 -->
<HotPanel :list="hotList" />
<!-- 猜你喜欢 -->
<XtxGuess />
</scroll-view>
</template>
<style lang="scss">
page {
background-color: #f7f7f7;
height: 100%;
display: flex;
flex-direction: column;
}
.scroll-view {
flex: 1;
}
</style>
调用组件对应后端API
单个页面内部使用组件采用页面内部调用API
1
2
3
4
5
6
//页面加载
onLoad(() => {
getHomeBannerData()
getHomeCategoryAPIData()
getHomeHotData()
})
多个页面内部都会用到的组件采用组件内部调用API
1
2
3
4
// 组件挂载完毕
onMounted(() => {
getHomeGoodsGuessLikeAPI()
})