小程序开发笔记

今天开始接触了小程序开发,直接上手做有点费劲,找个项目学着先做一遍吧….

**笔记中的项目内容部分来自b站up主咸虾米_分享的vue3+uniapp学习内容 **

记录下一些基础内容,不熟练容易忘

pages目录下放小程序页面内容

static静态文件

pages.json配置页面路由、导航栏、tabBar等页面类信息

在pages.json中,pages是页面路由及窗口表现,globalStyle是默认(全局)窗口表现,tabBar是下面的tab栏,至少要两个才会展示

manifest.json配置appid、应用名、logo、版本等打包信息

在manifest.json里面配置了appid后,微信开发工具的预览模式才能使用

swiper轮播图的使用,自动轮播,无缝衔接,点击查看预览

<template>
<swiper class="banner" indicator-dots :autoplay="false" circular>
<swiper-item v-for="item in pictures" :key="item.id">
<image :src="item.url" @tap="onPreviewImage(item.url)" />
</swiper-item>
</swiper>
</template>

<script>
export default {
data() {
return {
// 轮播图
pictures: [
{ id: 1, url: 'https://xxx' },
{ id: 2, url: 'https://xxx'}
]
}
},
onLoad() {
},
methods: {
onPreviewImage(url) {
// console.log(url)
uni.previewImage({
urls: this.pictures.map(item => item.url),
current: url
})
}
}
}
</script>

<style>
.banner {
width: 750rpx;
height: 750rpx;
}
.banner image {
width: 750rpx;
height: 750rpx;
}
</style>

使用即时设计进行尺寸测量

切片工具

可以用来测量字号、图片尺寸等

切片工具1

切片工具2

切片工具3

设置全局样式文件

项目目录中有一个文件叫uni.scss,这个就是小程序的全局样式文件,修改这个文件后想要使用其中变量需要重新启动项目

为了让内容干净,这里另写一个文件,然后再uni.scss中引用

/**
* cyk
*/
@import "@/common/style/base-style.scss";

banner海报swiper轮播器

实现效果

swiper轮播器

代码如下

<template>
<view class="homeLayout pageBg">
<view class="banner">
<swiper indicator-dots indicator-color="rgba(255,255,255,0.5)" indicator-active-color="#fff" autoplay circular>
<swiper-item v-for="item in imageList">
<image :src="item" mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
</template>

<script setup>
// 随便弄几张图
const imageList = ['../../common/images/banner1.jpg', '../../common/images/banner2.jpg', '../../common/images/banner3.jpg']
</script>

<style lang="scss" scoped>
.banner {
width: 750rpx;
padding: 30rpx 0;

swiper {
width: 750rpx;
height: 340rpx;

&-item {
width: 100%;
height: 100%;
padding: 0 30rpx;

image {
width: 100%;
height: 100%;
// 圆角
border-radius: 10rpx;
}
}
}

}
</style>

indicator-dots是轮播小圆点,indicator-color设置颜色,indicator-active-color是选中时的颜色,autoplay自动轮播,circular循环轮播

使用图片时,设置mode="aspectFill"让他撑满区域

使用swiper纵向轮播做公告区域

实现效果

`swiper`纵向轮播1

`swiper`纵向轮播2

代码内容

<template>
<view class="notice">
<view class="left">
<uni-icons type="sound-filled" size="20"></uni-icons>
<text class="text">公告</text>
</view>
<view class="center">
<swiper vertical autoplay interval="1500" duration="300" circular>
<swiper-item v-for="item in 4">文字内文字文字文字文字文字文字文字文字容</swiper-item>
</swiper>
</view>
<view class="right">
<uni-icons type="right" size="16" color="#333"></uni-icons>
</view>
</view>
</template>

<style lang="scss" scoped>
.notice {
width: 690rpx;
height: 80rpx;
line-height: 80rpx;
background: #f8f8f8;
margin: 0 auto;
border-radius: 80rpx;
display: flex;

.left {
width: 140rpx;
display: flex;
align-items: center;
justify-content: center;
:deep() {
.uni-icons {
color: $brand-theme-color !important;
}
}


.text {
color: $brand-theme-color;
font-weight: 600;
font-size: 28rpx;
}
}
.center {
flex: 1;

swiper {
height: 100%;

&-item {
height: 100%;
font-size: 30rpx;
color: #666;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
.right {
width: 70rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>

<uni-icons>是uniapp的图标组件,使用的话需要安装,基本用法如下

<uni-icons type="contact" size="30"></uni-icons>

type是图标类型,size图标大小,可以根据文档添加其他参数,如color修改图标颜色等

主要通过样式实现排列,其中displayalign-itemsjustify-content的设置保证元素所在位置居中,会经常使用

display: flex;
align-items: center;
justify-content: center;

在最外层添加了border-radius圆角,内部元素必须进行相关设置以展示圆角,比如上面在swiper-item设置的overflow: hidden;

另外,为公告部分内容添加了省略号的处理

white-space: nowrap;	// 阻止文本换行
text-overflow: ellipsis;

每日推荐使用scroll-view滑动布局

实现效果

`scroll-view`滑动布局

代码内容

<template>
<view class="homeLayout pageBg">
<view class="select">
<common-title>
<template #name>每日推荐</template>
<template #custom>
<view class="date">
<uni-icons type="calendar" size="18"></uni-icons>
<view class="text">
<uni-dateformat :date="Date.now()" format="dd日"></uni-dateformat>
</view>
</view>
</template>
</common-title>
<view class="content">
<scroll-view scroll-x>
<view class="box" v-for="item in 8">
<image src="../../common/images/preview_small.webp" mode="aspectFill"></image>
</view>
</scroll-view>
</view>
</view>
</view>
</template>


<style lang="scss" scoped>
.homeLayout {
.select {
padding-top: 50rpx;

.content {
width: 720rpx;
margin-left: 30rpx;
margin-top: 30rpx;

scroll-view {
white-space: nowrap;

.box {
width: 200rpx;
height: 430rpx;
display: inline-block;
margin-right: 15rpx;

image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
}

.box:last-child {
margin-right: 30rpx;
}
}
}

.date {
color: $brand-theme-color;
display: flex;
align-items: center;
:deep() {
.uni-icons {
color: $brand-theme-color !important;
}
}

.text {
margin-left: 5rpx;
}
}
}
}
</style>

具名插槽定义标题组件

添加了一个common-title组件,用来设置样式

<template>
<view class="common-title">
<view class="name">
<slot name="name">

</slot>
</view>
<view class="custom">
<slot name="custom"></slot>
</view>
</view>
</template>

<script setup>

</script>

<style lang="scss" scoped>
.common-title {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;

.name {
font-size: 40rpx;
}
}
</style>

这里分为上下两部分,上部分标题文字和日期,下部分是滑动组件

在上部分的日期这里,使用了uni-dateformat组件,也是需要先去uniapp组件市场安装

<!-- 一般用法 -->
<uni-dateformat date="2020/10/20 20:20:20"></uni-dateformat>

<!-- 不显示刚刚/马上/xx分钟前 -->
<uni-dateformat date="2020/10/20 20:20:20" :threshold="[0,0]"></uni-dateformat>

下部分使用scroll-view滚动条,指定scroll-x横向滚动,其中内容暂时用一个图片的循环

<view class="box" v-for="item in 8">
<image src="../../common/images/preview_small.webp" mode="aspectFill"></image>
</view>

为其设置white-space: nowrap;阻止换行

统一设置了右边距margin-right: 15rpx;,让每一个元素之间间隔15rpx,但是当滚动到最后一个元素时,右边距仍然为15rpx,而父元素左边距为30rpx,看起来不协调,所以单独调整最后一个元素的右边距

.box {
width: 200rpx;
height: 430rpx;
display: inline-block;
margin-right: 15rpx;

image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
}

.box:last-child {
margin-right: 30rpx;
}

磨砂背景 + 定位布局做专题组件

实现效果

代码内容

<template>
<view class="theme">
<common-title>
<template #name>专题精选</template>
<template #custom>
<navigator url="" class="more">more</navigator>
</template>
</common-title>

<view class="content">
<theme-item v-for="item in 8"></theme-item>
<theme-item :isMore="true"></theme-item>
</view>
</view>
</template>

<script setup>

</script>

<style lang="scss" scoped>
.theme {
padding: 50rpx 0;

.more {
font-size: 32rpx;
color: $text-font-color-3;
}

.content {
margin-top: 30rpx;
padding: 0 30rpx;
display: grid;
gap: 15rpx;
grid-template-columns: repeat(3, 1fr);
}
}
</style>

其中组件theme-item

<template>
<view class="themeItem">
<navigator url="/pages/classlist/classlist" class="box" v-if="!isMore">
<image class="pic" src="../../common/images/classify1.jpg" mode="aspectFill"></image>
<view class="mask">明星美女</view>
<view class="tab">3天前更新</view>
</navigator>

<navigator url="/pages/classify/classify" open-type="reLaunch" class="box more" v-if="isMore">
<image class="pic" src="../../common/images/more.jpg" mode="aspectFill"></image>
<view class="mask">
<uni-icons type="more-filled" size="34" color="#fff"></uni-icons>
<view class="text">更多</view>
</view>
</navigator>
</view>
</template>

<script setup>
defineProps({
isMore: {
type: Boolean,
default: false
}
})
</script>

<style lang="scss" scoped>
.themeItem {
.box {
height: 340rpx;
border-radius: 10rpx;
overflow: hidden;
position: relative;

.pic {
width: 100%;
height: 100%;
}

.mask {
width: 100%;
height: 70rpx;
position: absolute;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.2);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(20rpx);
font-weight: 600;
font-size: 30rpx;
}

.tab {
position: absolute;
left: 0;
top: 0;
background: rgba(250, 129, 90, 0.7);
backdrop-filter: blur(20rpx);
color: #fff;
font-size: 22rpx;
padding: 6rpx 14rpx;
border-radius: 0 0 20rpx 0;
transform: scale(0.8);
transform-origin: left top;
}
}

.box.more {
.mask {
width: 100%;
height: 100%;
flex-direction: column;
}

.text {
font-size: 28rpx;
}
}
}
</style>

首先,主页面中content部分,使用gird布局,grid-template-columns中,repeat(3, 1fr)表示创建3列,其中每份占据1/3空间,gap表示内容间距为15rpx

.content {
margin-top: 30rpx;
padding: 0 30rpx;
display: grid;
gap: 15rpx;
grid-template-columns: repeat(3, 1fr);
}

然后是组件中内容,根据父组件传递的参数isMore判断生成的内容,父组件中先循环了8次,且没有传递isMore,则默认生成图片为classify1.jpgnavigator跳转区域,这部分有一个遮罩的部分,使用定位设置遮罩位于父组件最下面区域,然后设置了遮罩的backgroundrgba(0, 0, 0, 0.2)是一个黑色的半透明区域,但是半透明还是可以看到遮罩后的内容的,所以添加backdrop-filter: blur(20rpx);为遮罩添加了一个模糊效果

.mask {
width: 100%;
height: 70rpx;
position: absolute;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.2);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(20rpx);
font-weight: 600;
font-size: 30rpx;
}

父组件循环8次后,单独定义了一个theme-item,并且传参isMoretrue,生成了内容为more.jpg跳转区域,并设置了单独的遮罩样式,这部分作为更多选项,所以遮罩设置为整个图片的遮罩,里面添加了一个。。。的的图标和更多文字,我希望他们竖向排列,所以修改flex布局为竖向flex-direction: column;,其余样式延用公共定义boxmask的样式,只有被boxmore同时修饰的元素才适用这些个性的样式

.box.more {
.mask {
width: 100%;
height: 100%;
flex-direction: column;
}

.text {
font-size: 28rpx;
}
}

点击更多时,希望跳转到分类的页面,但是分类位于tabBar中,默认是不允许跳转的,需要为navigator添加open-type="reLaunch"

<navigator url="/pages/classify/classify" open-type="reLaunch" class="box more" v-if="isMore">
<image class="pic" src="../../common/images/more.jpg" mode="aspectFill"></image>
<view class="mask">
<uni-icons type="more-filled" size="34" color="#fff"></uni-icons>
<view class="text">更多</view>
</view>
</navigator>

个人中心页面布局

头部logo部分

实现效果

用户头部

代码内容

<template>
<view class="userInfo">
<view class="avatar">
<image src="../../static/images/xxmLogo.png" mode="aspectFill"></image>
</view>

<view class="ip">100.100.100.100</view>

<view class="address">来自于: 山东</view>
</view>
</template>
<script setup>

</script>

<style lang="scss" scoped>
.userInfo {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 50rpx 0;

.avatar {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
overflow: hidden;

image {
width: 100%;
height: 100%;
}
}

.ip {
font-size: 44rpx;
color: #333;
padding: 20rpx 0 5rpx;
}

.address {
font-size: 28rpx;
color: #aaa;
}
}
</style>

通过样式调整头像、ip和地址的效果

内容部分

实现效果

代码内容

<template>
<view class="section">
<view class="list">
<navigator url="/pages/classlist/classlist" class="row">
<view class="left">
<uni-icons type="download-filled" size="20"></uni-icons>
<view class="text">我的下载</view>
</view>

<view class="right">
<view class="text">33</view>
<uni-icons type="right" size="15" color="#aaa"></uni-icons>
</view>
</navigator>

<navigator url="/pages/classlist/classlist" class="row">
<view class="left">
<uni-icons type="star-filled" size="20"></uni-icons>
<view class="text">我的评分</view>
</view>

<view class="right">
<view class="text">33</view>
<uni-icons type="right" size="15" color="#aaa"></uni-icons>
</view>
</navigator>

<view class="row">
<view class="left">
<uni-icons size="20"></uni-icons>
<view class="text">联系客服</view>
</view>
<view class="right">
<uni-icons type="right" size="15" color="#aaa"></uni-icons>
</view>
</view>
</view>
</view>
</template>
<script setup>
</script>

<style lang="scss" scoped>
.section {
width: 690rpx;
margin: 50rpx auto;
border: 1px solid #eee;
border-radius: 10rpx;
box-shadow: 0 0 30rpx eeergba(0, 0, 0, 0.05);
:deep() {
.uni-icons {
color: $brand-theme-color !important;
}
}

.list {
.row {
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
height: 100rpx;
border-bottom: 1px solid #eee;
position: relative;

&:last-child {
border-bottom: 0;
}

.left {
display: flex;
align-items: center;

.text {
padding-left: 20rpx;
color: #666;
}
}

.right {
display: flex;
align-items: center;

.text {
font-size: 28rpx;
color: #aaa;


}
}
}
}
}
</style>

每行的内容可以分为三个部分:内容图标、文字和最右侧的>,同时最右侧可能会有数字

那么将每一行分为左右两部分,.row中的justify-content: space-between;会让子元素会均匀地分布在容器内,第一个元素和最后一个元素贴靠容器的两端,中间的元素则根据可用空间均匀分布。

联系客服的功能,想要做成在小程序点击联系客服,在h5点击时拨打电话的,之后再说

#ifdef实现多端客服

代码内容

<template>
<view class="row">
<view class="left">
<uni-icons type="chatboxes-filled" size="20"></uni-icons>
<view class="text">联系客服</view>
</view>
<view class="right">
<uni-icons type="right" size="15" color="#aaa"></uni-icons>
</view>
<!-- #ifdef MP -->
<button open-type="contact">联系客服</button>
<!-- #endif -->
<!-- #ifndef MP -->
<button @click="clickContact">拨打电话</button>
<!-- #endif -->

</view>
</template>
<script setup>
const clickContact = () => {
uni.makePhoneCall({
phoneNumber: "114"
})
}
</script>

<style lang="scss" scoped>
.list {
.row {
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
height: 100rpx;
border-bottom: 1px solid #eee;
position: relative;

&:last-child {
border-bottom: 0;
}

.left {
display: flex;
align-items: center;

.text {
padding-left: 20rpx;
color: #666;
}
}

.right {
display: flex;
align-items: center;

.text {
font-size: 28rpx;
color: #aaa;


}
}

button {
position: absolute;
top: 0;
left: 0;
height: 100rpx;
width: 100%;
opacity: 0;
}
}
}
}
</style>

联系客服功能,这里思路是将联系客服这个区域都作为点击区域,那么直接弄一个透明的大按钮覆盖整个view区域就可以了

小程序内自身有客服相关的api,首先需要在小程序管理平台设置客服

小程序客服

然后为button添加open-type="contact"即可

<button open-type="contact">联系客服</button>

在h5页面是无法点击后跳转联系客服的聊天的,所以设置在h5点击时拨打电话,也可以在uniapp找的相关接口

拨打电话

再写另外一个按钮并且给他绑定点击事件

<button @click="clickContact">拨打电话</button>

<script setup>
const clickContact = () => {
uni.makePhoneCall({
phoneNumber: "114"
})
}
</script>

这样的话功能就实现了,那么接下来要控制他们分别在该生效的时候生效,就要用到#ifdef控制了

#ifdef#ifndef 是用于条件编译的指令。它们用于根据不同的平台或环境执行特定的代码块,从而在多平台或跨平台应用开发中提供灵活的代码处理机制。

常见平台标识符:

  • **MP**:通用小程序(包括微信、支付宝、百度等多端小程序)。
  • **H5**:H5 端(浏览器访问)。
  • **APP-PLUS**:App 端(运行在 iOS 或 Android 上的应用)。
  • **WEIXIN**:微信小程序。
  • **ALIPAY**:支付宝小程序。
  • **MP-WEIXIN**:专门用于微信小程序的标识符。
  • **MP-ALIPAY**:专门用于支付宝小程序的标识符。

那么就可以设置是小程序时#ifdef MP按钮功能是联系客服,不是小程序#ifndef MP时是拨打电话功能

<!-- #ifdef MP -->
<button open-type="contact">联系客服</button>
<!-- #endif -->
<!-- #ifndef MP -->
<button @click="clickContact">拨打电话</button>
<!-- #endif -->

最后在样式中设置button,宽度拉满,高度为100rpxrow相同,实现让整个按钮盖在整个联系客服区域,设置opacity: 0;,让按钮变得完全透明,实现需求

linear-gradient设置全局渐变背景色

首先在小程序主文件App.vue引入样式文件,可以在整个小程序中生效

渐变背景

然后写一个样式

.pageBg {
background:
linear-gradient(to bottom, transparent, #fff 400rpx),
linear-gradient(to right, #beecd8 20%, #F4E2D8);
min-height: 80vh;
}

linear-gradient 是 CSS 中用于创建线性渐变的函数。它可以让一种颜色平滑地过渡到另一种颜色,并且这种渐变可以在不同的方向上进行,比如从上到下、从左到右、或者任意角度。

linear-gradient 基本语法

background: linear-gradient(direction, color-stop1, color-stop2, ...);
  • **direction**:定义渐变的方向(默认是从上到下)。
  • **color-stop**:指定渐变的颜色及其位置(可选)。如果不指定位置,颜色会均匀分布。
方向(Direction)
  • 关键字
    • to top:从下到上渐变。
    • to bottom:从上到下渐变(默认方向)。
    • to left:从右到左渐变。
    • to right:从左到右渐变。
background: linear-gradient(to right, red, blue);
  • 角度: 角度值表示从水平线开始顺时针旋转的角度。0deg 是从下到上,90deg 是从左到右。
    • 0deg:从下到上渐变。
    • 90deg:从左到右渐变。
    • 180deg:从上到下渐变。
    • 270deg:从右到左渐变。
background: linear-gradient(45deg, red, blue);
颜色停止点(Color Stops)

每个渐变都至少需要两个颜色。颜色可以指定渐变的开始和结束位置,位置可以是百分比或长度值(如 px, em)。

  • 颜色:颜色可以用常见的色值表示法,如名字(red)、十六进制(#ff0000)、RGB(rgb(255,0,0))等。
  • 位置:可选项,表示颜色在哪个位置开始或结束渐变。如果不指定,颜色会根据数量平均分布。
background: linear-gradient(to right, red 0%, blue 100%);

更复杂的就不说了

这个是可以添加多个的,写多个linear-gradient就可以让渐变叠加

其中pageBg中的第一个渐变是从上到下的透明到白色渐变,第二个渐变是从左到右的绿色到米色渐变

linear-gradient(to bottom, transparent, #fff 400rpx), //从上到下透明到白色,渐变长度为 400rpx
linear-gradient(to right, #beecd8 20%, #F4E2D8); //从左到右绿色到米色,渐变将在距离左侧 20% 的位置处从 #beecd8 过渡到 #F4E2D8

最后为每个页面加上这个样式就可以了

<template>
<view class="xxxstyle pageBg">
</view>
</template>

路由页面跳转

这个简单,直接给navigator添加url就行了

<navigator url="/pages/classlist/classlist" class="row">

uni-popup弹出层

代码内容

<template>
<uni-popup ref="scorePopup">
<view class="scorePopup">
<view class="popHeader">
<view></view>
<view class="title">壁纸评分</view>
<view class="close" @click="clickScoreClose">
<uni-icons type="closeempty" size="18" color="#999"></uni-icons>
</view>
</view>
</view>
</uni-popup>
</template>

<script setup>
import { ref } from 'vue';

const scorePopup = ref(null)

// 打开评分弹窗
const clickScore = () => {
scorePopup.value.open();
}
// 关闭评分弹窗
const clickScoreClose = () => {
scorePopup.value.close();
}
</script>

首先要安装uni-popup的插件,官方文档的使用方法如下,这是vue2的写法

<template>
<view>
<button @click="open">打开弹窗</button>
<uni-popup ref="popup" type="bottom" border-radius="10px 10px 0 0">底部弹出 Popup 自定义圆角</uni-popup>
</view>
</template>
<script>
export default {
methods:{
open(){
// 通过组件定义的ref调用uni-popup方法 ,如果传入参数 ,type 属性将失效 ,仅支持 ['top','left','bottom','right','center']
this.$refs.popup.open('top')
}
}
}
</script>

哈哈,太久没写,挖坟了