uni-app运行到浏览器没有响应式
默认情况,需要在敲完代码以后,保存一下,浏览器才会有响应。也可以设置保存。
uni-app 与 Vue 开发的比较
| 不同点 | uni-app | Vue |
|---|---|---|
| 搭建项目 | HBuilder新建项目 | vue/cli |
| UI | 原生组件 或 uni-ui | ui组件库 |
| 路由管理 | page.json中直接配置 | vue router |
| 状态管理 | 内置 直接用 | vuex |
| 组件标签名 | <view><text><navigator> | <div><span><a> |
| JS API | 内置 uni.request( ) | AJAX axios |
uni-app路由配置
// pages.json
{
"pages": [ //pages数组中第一项表示应用启动页
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "抽奖"
}
},
{
"path": "pages/setting/setting",
"style": {
"navigationBarTitleText": "设置",
"enablePullDownRefresh": false
}
}
],
"tabBar": { //配置页面tab切换导航
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/home.png",
"selectedIconPath": "static/home.png",
"text": "抽奖"
}, {
"pagePath": "pages/setting/setting",
"iconPath": "static/setting-select.png",
"selectedIconPath": "static/setting-select.png",
"text": "设置"
}]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}
写 抽奖UI-数字呈现
// pages/index/index.vue
<template>
<view class="content">
<view class="panel">
<text>{{num}}</text>
</view>
<view class="button-area">
<button v-show="isOver" @click="start">开始抽奖</button >
<button v-show="!isOver" @click="stop">结束抽奖</button >
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello 突破',
num:40,
min:0, // 随机范围 [0, 100)
max:100,
interval:100, //ms
isOver:true,
clock:null
}
},
onLoad() {
},
onShow() {
let setting = uni.getStorageSync('setting') || {max:this.max, min:this.min, interval:this.interval}
this.max = setting.max
this.min = setting.min
this.interval = setting.interval
},
methods: {
start(){
this.isOver = false
this.clock = setInterval(()=>{
this.num = this.getRandomNum()
}, this.interval)
},
stop(){
clearInterval(this.clock)
this.isOver = true
},
getRandomNum(){
return parseInt(this.min) + Math.floor(Math.random()*(parseInt(this.max) - parseInt(this.min)))
}
}
}
</script>
<style lang="scss">
.panel{
width: 600rpx;
height:400rpx;
border-radius: 8rpx;
margin-top: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border:1rpx solid $uni-border-color;
box-shadow: 0 0 40rpx 0 rgba(0, 0, 0, 0.1);
text{font-size: 100rpx;}
}
.button-area{
margin-top: 120rpx;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
- 最终效果
写设置页面
// pages/setting/setting.vue
<template>
<view class="content">
<view class="list">
<view class="uni-form-item uni-column">
<view class="title">最大值</view>
<input class="uni-input" v-model="max" type="number" placeholder="最大值" />
</view>
<view class="uni-form-item uni-column">
<view class="title">最小值</view>
<input class="uni-input" v-model="min" type="number" placeholder="最小值" />
</view>
<view class="uni-form-item uni-column">
<view class="title">时间间隔(ms)</view>
<input class="uni-input" v-model="interval" type="number" placeholder="时间间隔" />
</view>
<view class="button-area">
<button @click="onSave">保存</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
max:100,
min:0,
interval:100
}
},
created() {
let setting = uni.getStorageSync('setting') || {max:this.max, min:this.min, interval:this.interval}
this.max = setting.max
this.min = setting.min
this.interval = setting.interval
},
methods: {
onSave(){
let setting = {max:this.max, min:this.min, interval:this.interval}
uni.setStorageSync('setting', setting)
}
}
}
</script>
<style lang="scss">
.content{
padding: 40rpx;
}
.uni-form-item{
padding: 20rpx;
}
.uni-input{
border-bottom: 1px solid $uni-border-color;
margin-top: 16rpx;
font-size: 26rpx;
}
.button-area{
margin-top: 120rpx;
display: flex;
justify-content: center;
button{
width: 400rpx;
}
}
</style>
- 最终效果:
uniCloud
基于serverless模式和js编程的云开发平台
- 服务空间
- 云函数/云对象
- 云数据库
首次登陆账号使用uniCloud需要实名认证
- 创建云服务空间
- 在
uniCloud上创建数据库表schema,配置好点保存
- 表结构为
{
"bsonType": "object",
"permission": {
"read": true,
"create": true,
"update": true,
"delete": true
},
"required": [ // schema2code时加校验,选项是必填项
"title"
],
"properties": {
"_id": {
"description": "存储文档 ID(用户 ID),系统自动生成"
},
"title":{
"bsontype":"string",
"title":"名称",
"description":"输入奖品名称"
}
},
"version": "0.0.1"
}
- 在
HBuilder上创建数据库表schema,创建好上传,同步uniCloud
- 新建项目时,在模板页勾选 启用uniCloud
- 创建时未勾选的,项目目录上右键 创建uniCloud云开发环境(aliyun),直接生成后端部分,云函数、云数据库;右键文件夹关联云服务空间或项目
- 在云函数文件夹上,右键下载所有云函数、公共模块及actions
- 在云数据库文件夹上,右键下载所有DB Schema及扩展校验函数,此时就会把之前在云端的配置,同步到编辑器中
lottery-schema.json
schema2code 自动生成代码
- 本地
lottery-schema.json文件上右键 选择schema2code,会自动生成pages/lottery文件夹,会提示把新增的page注册到路由表中 - pages文件夹下,新生成文件:
- 运行到浏览器查看上述自动生成的文件的效果是否实现。
前端操作数据库
用unicloud-db组件,把前端和数据库连接。
- List列表页为例:
unicloud-db组件通过绑定collection对应的collectionList,建立数据表lottery的链接;也是clientDB请求,表名为lottery,返回数据:
{
"code": 0,
"errCode": 0,
"message": "",
"errMsg": "",
"systemInfo": [],
"affectedDocs": 2,
"data": [{
"_id": "634037246758c00001cb24ae",
"title": "air 笔记本"
}, {
"_id": "6340374960cd3e000116e946",
"title": "靠枕"
}],
"timeCost": 166
}
// pages/lottery/list.vue
<template>
<view class="container">
<unicloud-db ref="udb" v-slot:default="{data, pagination, loading, hasMore, error}" :collection="collectionList" field="title">
<view v-if="error">{{error.message}}</view>
<view v-else-if="data">
<uni-list>
<uni-list-item v-for="(item, index) in data" :key="index" showArrow :clickable="true" @click="handleItemClick(item._id)">
<template v-slot:body>
<text>
<!-- 此处默认显示为_id,请根据需要自行修改为其他字段 -->
<!-- 如果使用了联表查询,请参考生成的 admin 项目中 list.vue 页面 -->
{{item._id}}
</text>
</template>
</uni-list-item>
</uni-list>
</view>
<uni-load-more :status="loading?'loading':(hasMore ? 'more' : 'noMore')"></uni-load-more>
</unicloud-db>
<uni-fab ref="fab" horizontal="right" vertical="bottom" :pop-menu="false" @fabClick="fabClick" />
</view>
</template>
<script>
const db = uniCloud.database()
export default {
data() {
return {
collectionList: "lottery",
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
}
}
},
onPullDownRefresh() { // 手机端 下拉刷新
this.$refs.udb.loadData({
clear: true
}, () => {
uni.stopPullDownRefresh()
})
},
onReachBottom() {
this.$refs.udb.loadMore()
},
methods: {
handleItemClick(id) {
uni.navigateTo({
url: './detail?id=' + id
})
},
fabClick() {
// 打开新增页面
uni.navigateTo({
url: './add',
events: {
// 监听新增数据成功后, 刷新当前页面数据
refreshData: () => {
this.$refs.udb.loadData({
clear: true
})
}
}
})
}
}
}
</script>
重新生成代码合并
可以手动选择是否要修改
在schema上增加图片上传的操作,重新生成schema2code勾选全部文件合并后
// lottery.schema.json
{
"bsonType": "object",
"permission": {
"read": true,
"create": true,
"update": true,
"delete": true
},
"required": ["title", "photo"], // 新增 photo
"properties": {
"_id": {
"description": "存储文档 ID(用户 ID),系统自动生成"
},
"title": {
"bsonType": "string",
"title": "名称",
"description": "输入奖品名称"
},
"photo":{ // 新增 photo
"bsonType":"file",
"title": "图片",
"fileMediaType": "image",
"fileExtName":"jpg,png"
}
},
"version": "0.0.1"
}
- 图片上传完毕后,列表展示每个
item
// pages/lottery/list.vue
<template v-slot:body>
<text>
{{item.title}}
<image :src="item.photo.url" model="aspectFill"></image>
</text>
</template>
写 抽奖UI-图片呈现
- 借鉴
list.vue的结构
// pages/index/index.vue
<template>
<view class="content">
<unicloud-db ref="udb" v-slot:default="{data, pagination, loading, hasMore, error}" :collection="collectionList" field="title,photo">
<view v-if="error">{{error.message}}</view>
<view v-else-if="data">
<uni-list>
<uni-list-item v-for="(item, index) in data" :key="index">
<template v-slot:body>
<text>
<!-- 此处默认显示为_id,请根据需要自行修改为其他字段 -->
<!-- 如果使用了联表查询,请参考生成的 admin 项目中 list.vue 页面 -->
{{item.title}}
<image :src="item.photo.url" model="aspectFill"></image>
</text>
</template>
</uni-list-item>
</uni-list>
</view>
<uni-load-more :status="loading?'loading':(hasMore ? 'more' : 'noMore')"></uni-load-more>
</unicloud-db>
<view class="panel">
<text>{{num}}</text>
</view>
<view class="button-area">
<button v-show="isOver" @click="start">开始抽奖</button >
<button v-show="!isOver" @click="stop">结束抽奖</button >
</view>
</view>
</template>
<script>
export default {
data() {
return {
collectionList:"lottery",
num:40,
min:0, // 随机范围 [0, 100)
max:100,
interval:100, //ms
isOver:true,
clock:null,
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
}
}
},
onLoad() {
},
onShow() {
let setting = uni.getStorageSync('setting') || {max:this.max, min:this.min, interval:this.interval}
this.max = setting.max
this.min = setting.min
this.interval = setting.interval
},
onPullDownRefresh() {
this.$refs.udb.loadData({
clear: true
}, () => {
uni.stopPullDownRefresh()
})
},
onReachBottom() {
this.$refs.udb.loadMore()
},
methods: {
start(){
this.isOver = false
this.clock = setInterval(()=>{
this.num = this.getRandomNum()
}, this.interval)
},
stop(){
clearInterval(this.clock)
this.isOver = true
},
getRandomNum(){
return parseInt(this.min) + Math.floor(Math.random()*(parseInt(this.max) - parseInt(this.min)))
}
}
}
</script>
<style lang="scss">
.panel{
width: 600rpx;
height:400rpx;
border-radius: 8rpx;
margin-top: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border:1rpx solid $uni-border-color;
box-shadow: 0 0 40rpx 0 rgba(0, 0, 0, 0.1);
text{font-size: 100rpx;}
}
.button-area{
margin-top: 120rpx;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
- 加样式,图片呈宫格显示
<template>
<view class="content">
<unicloud-db ref="udb" v-slot:default="{data, pagination, loading, hasMore, error}" :collection="collectionList" field="title,photo">
<view v-if="error">{{error.message}}</view>
<view v-else-if="data">
<uni-list class="list">
<uni-list-item v-for="(item, index) in data" :key="index">
<template v-slot:body>
<view class="item">
<!-- 此处默认显示为_id,请根据需要自行修改为其他字段 -->
<!-- 如果使用了联表查询,请参考生成的 admin 项目中 list.vue 页面 -->
<view>
<image :src="item.photo.url" model="aspectFill"></image>
</view>
<view>
{{item.title}}
</view>
</view>
</template>
</uni-list-item>
</uni-list>
</view>
<uni-load-more :status="loading?'loading':(hasMore ? 'more' : 'noMore')"></uni-load-more>
</unicloud-db>
<view class="button-area">
<button v-show="isOver" @click="start">开始抽奖</button >
<button v-show="!isOver" @click="stop">结束抽奖</button >
</view>
</view>
</template>
<script>
export default {
data() {
return {
collectionList:"lottery",
num:40,
min:0, // 随机范围 [0, 100)
max:100,
interval:100, //ms
isOver:true,
clock:null,
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
}
}
},
onLoad() {
},
onShow() {
let setting = uni.getStorageSync('setting') || {max:this.max, min:this.min, interval:this.interval}
this.max = setting.max
this.min = setting.min
this.interval = setting.interval
},
onPullDownRefresh() {
this.$refs.udb.loadData({
clear: true
}, () => {
uni.stopPullDownRefresh()
})
},
onReachBottom() {
this.$refs.udb.loadMore()
},
methods: {
start(){
this.isOver = false
this.clock = setInterval(()=>{
this.num = this.getRandomNum()
}, this.interval)
},
stop(){
clearInterval(this.clock)
this.isOver = true
},
getRandomNum(){
return parseInt(this.min) + Math.floor(Math.random()*(parseInt(this.max) - parseInt(this.min)))
}
}
}
</script>
<style lang="scss">
.content{
.uni-list{
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
}
.item{
text-align: center;
image{
width: 200rpx;
height: 200rpx;
}
}
.panel{
width: 600rpx;
height:400rpx;
border-radius: 8rpx;
margin-top: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border:1rpx solid $uni-border-color;
box-shadow: 0 0 40rpx 0 rgba(0, 0, 0, 0.1);
text{font-size: 100rpx;}
}
.button-area{
margin-top: 120rpx;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
抽奖页图片抽奖功能
- 原来的抽奖UI-数字呈现 的逻辑要修改为现有图片,随机产生数据对应到图片上。借鉴uniCloud文档语法实例(传统nosql查询语法示例)
// 获取db引用
const db = uniCloud.database() //代码块为cdb
// 使用uni-clientDB
db.collection('list')
.where({
name: "hello-uni-app" //传统MongoDB写法,不是jql写法。实际开发中推荐使用jql写法
}).get()
.then((res)=>{
// res 为数据库查询结果
}).catch((err)=>{
console.log(err.code); // 打印错误码
console.log(err.message); // 打印错误内容
})
- 具体实现
// index.vue
created() {
this.$nextTick(() => {
db.collection(dbCollectionName)
.get()
.then((res) => { // res 为数据库查询结果
console.log(res)
})
})
}
- 重新调整路由表
//pages.json
{
"pages": [ //pages数组中第一项表示应用启动页
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "抽奖"
}
},
{
"path": "pages/lottery/list",
"style": {
"navigationBarTitleText": "设置",
"enablePullDownRefresh": false
}
}, {
"path": "pages/lottery/add",
"style": {
"navigationBarTitleText": "新增"
}
}, {
"path": "pages/lottery/edit",
"style": {
"navigationBarTitleText": "编辑"
}
}, {
"path": "pages/lottery/list",
"style": {
"navigationBarTitleText": "列表"
}
}, {
"path": "pages/lottery/detail",
"style": {
"navigationBarTitleText": "详情"
}
}
],
"tabBar": { //配置页面tab切换导航
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/home.png",
"selectedIconPath": "static/home.png",
"text": "抽奖"
}, {
"pagePath": "pages/lottery/list",
"iconPath": "static/setting-select.png",
"selectedIconPath": "static/setting-select.png",
"text": "设置"
}]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}
- 优化样式
.content {
.uni-list {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: center;
}
}
.uni-list-item{
border:4rpx solid transparent ;
}
.active{
border-color: red;
}
- 最终效果图