目录结构如图所示
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": "我的"
}]
}
}
在uni-app插件市场 (opens new window)下载符合
components/组件名称/组件名称.vue
目录结构的组件,均可直接使用。
我们需要创建相同的文件结构
components/f-search-bar/f-search-bar.vue
然后直接在文件中使用<f-search-bar></f-search-bar>
即可,不需要引用
<uni-icons type="search" size="30"></uni-icons>
<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',
}
],,
<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>
使用 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>
<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]
}
}
...(省略)
复用拼团模块的页面
通过动态绑定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;
}
}
<image :src="item.data" mode="aspectFill" style="width: 750rpx; height: 360rpx;">
</image>
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()
}
});
}
在pages.json
中,找到首页
"path": "pages/tabbar/index/index",
"style": {
"enablePullDownRefresh": true,//添加这个参数
"app-plus": {
"titleNView": false //禁用原生导航栏
}
}
创建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)
})
},
}
// 响应拦截器
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)
})
}
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)
}
}
<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>
有一个小坑,在使用<uni-list>的<uni-list-item>
时候,会发现点击无效,需要进行clickable
的配置
<uni-list-item clickable title="设置" showArrow @click="openSetting">