Skip to content

Latest commit

 

History

History
676 lines (548 loc) · 13.3 KB

36.uniapp开发实录.md

File metadata and controls

676 lines (548 loc) · 13.3 KB

uniapp 开发实录

1、用HBX搭建模板

2、创建底部三个导航栏页面

目录结构如图所示

image-20220817162655467

pages.json

{
	"pages": [{
		"path": "pages/tabbar/index/index",
		"style": {
			"app-plus": {
				"titleNView": false //禁用原生导航栏
			}
		}
	}, {
		"path": "pages/tabbar/learn/learn",
		"style": {
			"navigationBarTitleText": "",
			"enablePullDownRefresh": false
		}
	}, {
		"path": "pages/tabbar/home/home",
		"style": {
			"navigationBarTitleText": "",
			"enablePullDownRefresh": false
		}
	}],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uniapp在线教育",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8",
		"app-plus": {
			"background": "#efeff4"
		}
	},
	"tabBar": {
		"color": "#BBBAC7",
		"selectedColor": "#2c2c2c",
		"borderStyle": "black",
		"list": [{
			"iconPath": "static/tabbar/index.png",
			"pagePath": "pages/tabbar/index/index",
			"selectedIconPath": "static/tabbar/index_selected.png",
			"text": "首页"
		}, {
			"iconPath": "static/tabbar/learn.png",
			"pagePath": "pages/tabbar/learn/learn",
			"selectedIconPath": "static/tabbar/learn_selected.png",
			"text": "学习"
		}, {
			"iconPath": "static/tabbar/home.png",
			"pagePath": "pages/tabbar/home/home",
			"selectedIconPath": "static/tabbar/home_selected.png",
			"text": "我的"
		}]
	}
}

3、使用easycom创建组件

uni-app插件市场 (opens new window)下载符合components/组件名称/组件名称.vue目录结构的组件,均可直接使用。

我们需要创建相同的文件结构

components/f-search-bar/f-search-bar.vue

然后直接在文件中使用<f-search-bar></f-search-bar>即可,不需要引用

4、使用 uni 图标

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

5、使用 swiper 轮播图组件

<swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
		<swiper-item class="flex justify-center" v-for="(item,index) in swiper" :key="index">
			<image :src="item.src" mode="aspectFill" 
                   style="width: 720rpx; height: 300rpx;"
                   class="rounded shadow">
			</image>
		</swiper-item>
</swiper>

script

swiper: [{
		src: '/static/demo/banner/banner1.png',
	},{
		src: '/static/demo/banner/banner2.png',
	}
],,

6、新增icon-nav

<templete>
    <view class="flex flex-wrap py-2">
		<view v-for="(item,index) in list" :key="index" style="width: 25%;" hover-class="bg-light"
			class="flex flex-column justify-center align-center py-1" >
			<image :src="item.src" mode="widthFix"
                   style="width: 70rpx; height: 70rpx; border-radius 100%;" >
			</image>
			<text class="font-sm text-muted mt-1">{{ item.name }}</text>
        </view>
    </view>
</templete>	

<script>
export default {
	name: "icon-nav",
	props: {
		list: Array,//通过 index 组件给导航栏图标传值
	},
	data() {
		return {};
	}
}
</script>

index组件

<template>
	<view>
		...(省略)
		<icon-nav :list="iconNav"></icon-nav>
	</view>
</template>
<script>
    export default{
        data() {
            return{
                ...(省略)
                iconNav: [{
					name: '活动',
					src: '/static/demo/icon/hd.png'
				}, {
					name: '考试',
					src: '/static/demo/icon/test.png'
				}, {
					name: '秒杀',
					src: '/static/demo/icon/ms.png'
				}, {
					name: '拼团',
					src: '/static/demo/icon/pt.png'
				}, {
					name: '直播',
					src: '/static/demo/icon/course.png'
				}, {
					name: '专栏',
					src: '/static/demo/icon/column.png'
				}, {
					name: '电子书',
					src: '/static/demo/icon/book.png'
				}, {
					name: '社区',
					src: '/static/demo/icon/ask.png'
				}]
            }
        }
    }
</script>

7、优惠券组件开发

使用 uniapp 提供的 <scroll-view> 横向滚动组件

<scroll-view scroll-x="true" class="scroll-row">
	<view style="width: 310rpx; display:inline-flex" v-for="i in 3" :key="i" class="text-white mr-3">
		<view class="flex flex-column align-center justify-center bg-hover-warning px-3 py-2"
              style="border-right: 3rpx dashed;">
			<text>¥100</text>
			<text class="font-sm">满¥200可用</text>
		</view>
		<view class="flex justify-center align-center bg-warning font-sm"style="width: 120rpx;">领取</view>
	</view>
</scroll-view>

8、拼团页面的开发

<template>
	<view class="scroll-row-item course cource-two">
		<view class="position-relative">
			<image :src="item.cover" mode=""></image>
			<view class=" text-light font-sm">{{item.type | formatType}}</view>
		</view>
		<view class="flex flex-column flex-shrink">
			<text class="text-ellipsis font-md mt-1">{{item.title}}</text>
			<!-- <view class="font-sm text-light-muted my-1">10人已枪</view> -->
			<view class="flex flex-1 align-end">
				<text class="font-md text-danger">¥{{ item.price }}</text>
				<text class="font-sm text-light-muted">¥{{ item.t_price }}</text>
			</view>
		</view>
	</view>
</template>

<style lang="scss">
	.course {}

	.cource-two {
		width: 340rpx;
		margin-left: 20rpx;
		margin-bottom: 20rpx;

		image,
		view:first-child {
			width: 340rpx;
			height: 180rpx;

			view {
				position: absolute;
				bottom: 10rpx;
				right: 10rpx;
				background: rgba(0, 0, 0, 0.4);
				paddnig: 0 10rpx;
			}
		}

	}
</style>

过滤器的使用

<view class=" text-light font-sm">{{item.type | formatType}}</view>
...(省略)
let opt = {
		media: "图文",
		audio: "音频",
		video: "视频",
		column: "专栏"
	}
filters: {
	formatType(k) {
		return opt[k]
	}
}
...(省略)

9、最新课程模块

复用拼团模块的页面

通过动态绑定class 实现不同的样式

<template>
	<view class="scroll-row-item course" :class="'course-'+this.type">
		...(省略)
	</view>
</template>

<script>
export default{
	props: {
        item: Object,
		type: {
			type: String,
			default: "two"
		}
	},
}
</script>

通过父组件index传值控制不同的样式

.course-one {
		display: flex !important;
		padding: 20rpx;

		image,
		view:first-child {
			width: 300rpx;
			height: 170rpx;
			flex-shrink: 1;

			view {
				position: absolute;
				bottom: 10rpx;
				right: 10rpx;
				background: rgba(0, 0, 0, 0.4);
				paddnig: 0 10rpx;
			}
		}

		view:first-child {
			margin-right: 20rpx;
		}
	}

10、底部广告组件

<image :src="item.data" mode="aspectFill" style="width: 750rpx; height: 360rpx;">
</image>

11、从后端获取数据

data() {
	return {
        ...(省略)
		templates: [], //暂存后端获取的数据
	}
},

created() {
	this.getData()
},
    
getData() {
	uni.request({
		url: 'http://demonuxtapi.dishait.cn/mobile/index',
		method: 'GET',
		header: {
			appid: " bd9d01ecc75dbbaaefce"
		},
		success: res => {
			// console.log(res);
			if (res.statusCode !== 200 || res.data.msg === 'fail') {
				uni.showToast({
					title: res.data.data || '请求失败',
					icon: 'none'
				});
				return
			}
			this.templates = res.data.data
		},
		fail: (err) => {
			console.log(err);
		},
		complete: () => {
			uni.stopPullDownRefresh()
		}
	});
}

12、配置下拉刷新

pages.json中,找到首页

"path": "pages/tabbar/index/index",
"style": {
	"enablePullDownRefresh": true,//添加这个参数
	"app-plus": {
		"titleNView": false //禁用原生导航栏
	}
}

13、配置请求拦截器

创建api目录,新建request.js

config: {
	baseURL: 'http://demonuxtapi.dishait.cn',
	appid: 'bd9d01ecc75dbbaaefce',
	// 请求拦截器
	beforeRequest(options = {}) {
		return new Promise((resolve, reject) => {
			// 公共参数处理
			options.url = this.baseURL + options.url
			options.method = options.method || 'GET'
			options.header = {
				appid: this.appid
			}
			// 权限相关验证
			resolve(options)
		})
	},
}

14、配置响应拦截器

// 响应拦截器
handleResponse([error, res]) {
	return new Promise((resolve, reject) => {
		// 错误提示处
		if (res.statusCode !== 200 || res.data.msg === 'fail') {
			let msg = res.data.data || '请求失败'
			uni.showToast({
				title: msg,
				icon: 'none'
			})
			return reject(msg)
		}
		resolve(res.data.data)
	})
}

15、每次发起请求调用拦截器

export default {
	config: {
		baseURL: 'http://demonuxtapi.dishait.cn',
		appid: 'bd9d01ecc75dbbaaefce',
		// 请求拦截器
		beforeRequest(options = {}) {
			return new Promise((resolve, reject) => {
				// 公共参数处理
				options.url = this.baseURL + options.url
				options.method = options.method || 'GET'
				options.header = {
					appid: this.appid
				}
				// 权限相关验证
				resolve(options)
			})
		},

		// 响应拦截器
		handleResponse([error, res]) {
			return new Promise((resolve, reject) => {
				// 错误提示处
				if (res.statusCode !== 200 || res.data.msg === 'fail') {
					let msg = res.data.data || '请求失败'
					uni.showToast({
						title: msg,
						icon: 'none'
					})
					return reject(msg)
				}
				resolve(res.data.data)
			})
		}

	},
	request(options = {}) {
		return this.config.beforeRequest(options).then(opt => uni.request(opt))
			.then(this.config.handleResponse)
	},

	// GET 请求
	get(url, params = {}, options = {}) {
		let temp = '?' + Object.keys(params).map(key => key + '=' + params[key]).join('&')
		options.url = url
		options.url += params ? temp : ''
		options.method = 'GET'
		return this.request(options)
	},

	// POST 请求
	post(url, data = {}, options = {}) {
		options.url = url
		options.method = 'POST'
		options.data = data
		return this.request(options)
	}
}

16、登录组件开发

<template>
	<view>
		<view class="login-back" @click="back">
			<uni-icons type="locked" size="20"></uni-icons>
		</view>
		<view class="login-bg"></view>
		<view class="login">
			<!-- 登录标题 -->
			<view class="flex">
				<text class="title">{{type==='login'?'登录':'注册'}}</text>
			</view>
			<!-- 用户名密码区域 -->
			<view class="login-form">
				<uni-icons type="person" size="20"></uni-icons>
				<input type="text" placeholder="请输入用户名" v-model="form.username" class="rounded font-md">
			</view>
			<view class="login-form">
				<uni-icons type="locked" size="20"></uni-icons>
				<input type="password" placeholder="请输入密码" v-model="form.password" class="rounded font-md">
			</view>

			<view class="login-form" v-if="type!=='login'">
				<uni-icons type="locked" size="20"></uni-icons>
				<input type="password" placeholder="请再次输入密码" v-model="form.repassword" class="rounded font-md">
			</view>
			<!-- 登录按钮 -->
			<view>
				<view class="bg-main btn" hover-class="bg-main-hover" @click="submit">
					{{type==='login'?'登 录':'注 册'}}
				</view>
			</view>

			<!-- 注册账号 忘记密码 -->
			<view class="flex align-center justify-between my-2 font">
				<text class="py-2 text-main" @click="changeType">{{type==='login'?'注册账号':'去登录'}}</text>
				<text class="py-2 text-light-muted">忘记密码?</text>
			</view>

			<!-- 微信登录 -->
			<view class="wechatlogin flex align-center justify-center">
				<uni-icons type="weixin" size="28" color="#5ccc84"></uni-icons>
			</view>

			<!-- 用户协议 -->
			<checkbox-group v-if=" type ==='login'" @change="hanCheckboxChange"
				class='flex align-center justify-center mt-3'>
				<label class="text-light-muted">
					<checkbox value="1" color="#7fd49e" style="transform: scale(0.7);" />
					<text class="font">已阅读并同意用户协议&隐私声明</text>
				</label>
			</checkbox-group>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				confirm: false,
				type: 'login',
				form: {
					username: 'johnny',
					password: 'johnny',
					repassword: ''
				}
			}
		},
		methods: {
			back() {
				uni.navigateBack({
					delete: 1
				});
			},
			changeType() {
				this.type = this.type === 'login' ? 'reg' : 'login'
			},

			resetForm() {
				this.form = {
					username: '',
					password: '',
					repassword: ''
				}
			},
			hanCheckboxChange(e) {
				this.confirm = !!e.detail.value.length
			},

			submit() {
				if (!this.confirm && this.type === 'login') {
					return this.$toast('请先阅读并同意用户协议&隐私声明')
				}
				uni.showLoading({
					title: '提交中',
					mask: false
				})
				let data = Object.assign(this.form, {})
				if (this.type === 'reg') {
					// console.log(data);
					this.$api.reg(data).then(res => {
						this.$toast('注册成功')
						this.resetForm()
						this.changeType()
					}).finally(() => {
						uni.hideLoading()
					})
				} else {
					this.$api.login(data).then(user => {
						// console.log(user)
						this.$toast('登录成功')
						this.$store.dispatch('login', user)
						setTimeout(() => {
							this.back()
						}, 350)
					}).finally(() => {
						uni.hideLoading()
					})
				}
			}
		}
	}
</script>

<style lang="scss">

</style>

17、我的 页面开发

有一个小坑,在使用<uni-list>的<uni-list-item>时候,会发现点击无效,需要进行clickable的配置

<uni-list-item clickable title="设置" showArrow @click="openSetting">