赞
踩
记录一下uni-app中常用的使用方法或是操作步骤,方便后期速查使用.
1.设置对象属性
2.组件中数据变化监听方法
3.微信开发者工具中全局搜索与局部搜索
4.Page对象与Componet对象组成
5.tabbar页面切换方法
6.组件中自定义函数的参数传递
7.mobx全局数据共享创建store对象实例
8.()=>含义
9.const { data: res }含义
10.Vue相关
10.1 v-bind与v-on绑定问题
10.2 import说明
10.3 定义全局变量
10.4 数据类型
10.5 v-if与v-show
10.6 v-html
10.7 v-bind
10.8 v-model
10.9 this.$refs使用方法
10.91 async与await
10.92 特殊语法之|| {}
10.93 特殊语法之config?.custom?.auth
11.样式相关
11.1图片或容器横向显示问题 display:flex
11.2子区域大小与父区域保持一致
11.3元素分布不均匀如何处理
11.4容器间距过小如何处理
11.5标签中设置style属性
11.6 image中自适应mode属性
11.7 image中多张图片换行显示
11.8 view默认选中以及样式动态绑定
11.9 文本居中
11.91 行间距设置
11.92 class绑定方式
11.93 vue中自定义函数方式
11.94 vue中使用scss样式
11.95 uniapp中view组件与text组件
11.96 动态切换案例
11.97 简单表单提交
11.98 computed属性计算
11.99 uiapp中props以及子父组件传值问题以及native sync修饰符
11.991 uiapp中页面跳转方式以及请求参数获取
11.992 uiapp中交互反馈
11.993 border常用样式
11.994 padding常用属性
11.995 uniapp中数据缓存
11.996 文字不换行以及行号和文字大小
11.997 微信聊天文本输入框固定聊天窗口底部显示
11.998 view水平居中
11.999 盒子水平放置并保持一定间隔
11.9991 view中背景颜色与字体颜色
11.9992 最外层view设置高度100%无效处理
11.9993 不同元素间隔一定距离的实现padding-left重新理解
11.9994 图片右上角添加小图标
11.9995 页面最外层容器设置高度100%占整个页面
11.9996 button样式修改
12.微信开发者工具中设置编译模式,重启后跳转指定页面
13.scroll-view中的高度样式问题
14.浏览器控制台打印内容显示object Object问题
15.数组拼接的两种方式
16.条件编译
17.环境判断
18.数据遍历map方法使用说明
19.判空undefined null 字符串空
20.时间格式化
21.同一页面多个函数之间如何进行参数传递
22.uniapp中success中不能调用this处理方案
23.uniapp中tabbar切换触发函数
24.uniapp中页面刷新
25.uniapp中数据修改后监听数据渲染完成方式
26.uniapp中封装全局公共方法
27.uniapp中request方法返回值获取问题
28.uniapp中success不支持await
不论是page对象还是componet对象,设置data中节点值的方式:
this.setData({
节点名:节点值
})
Component({
observers:{
'监听的数据字段名':function(自定义数据字段变化后的参数名){
// 打印监听字段变化之后的值
console.log(自定义数据字段变化后的参数名)
}
}
})
局部搜索,直接在打开的页面中Ctrl+f即为从当前打开页面搜索.
全局搜索:点击搜索按钮,点击打开新的搜索编辑器,输入搜索内容,可以显示命中关键字的文件以及具体位置,ctrl+鼠标点击可以进入文件内部.搜索步骤参考下图:
微信开发者工具中的显示大小是宽度*高度.
page对象常用参数:
Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady() { }, /** * 生命周期函数--监听页面显示 */ onShow() { }, /** * 生命周期函数--监听页面隐藏 */ onHide() { }, /** * 生命周期函数--监听页面卸载 */ onUnload() { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh() { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom() { }, /** * 用户点击右上角分享 */ onShareAppMessage() { } })
其余参数说明参考官方文档:
https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html
component对象常用参数:
Component({ /** * 组件的数据列表 */ data: { }, /** * 组件的属性列表 */ properties: { }, /** * 组件的方法列表 */ methods: { } } })
其余参数说明参考官方链接:
https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html
注意方法或是函数在两个对象中定义位置,page对象中方法定义与data节点同级,component对象中方法定义在methods节点中.
wx.switchTab({
url: 'url'
})
一般用于方法函数中调用
参数传递:组件标签中添加内容如下:
data-属性名='{{属性值}}'
js中回调事件event中参数获取:
event.target.dataset.属性名
注意:自定义属性不支持驼峰,js中获取的时候注意去驼峰.示例:
<button type="primary" bindtap="addNum" data-numInterval='{{5}}'>数字加5</button>
但是实际解析的时候就不再是驼峰了
js中获取:
addNum:function(event){
this.setData({
num:this.data.num+event.target.dataset.numinterval
})
}
创建前提是项目中导入mobx-miniprogram、mobx-miniprogram-bindings.
详细操作参考:uni-app入门:全局数据共享方案之mobx
store/store.js中创建store对象(observable用于创建store对象):
import {observable,action} from 'mobx-miniprogram'
// observable方法用于创建store对象(按照page对象添加),action方法用于定义共享的方法
// 创建store对象并导出的格式:export const store=observable({})
export const store=observable({
// 字段共享格式:字段名:字段值
num:2,
// 方法共享格式:方法名:action(function函数)即action(function(){})
updateNum:action(function(step){
this.num+=step;
})
})
page对象中绑定store对象(createStoreBindings方法用于绑定storeBindings)
// 导入创建store绑定方法 import {createStoreBindings} from 'mobx-miniprogram-bindings' // 导入store实例对象 import {store} from '../../store/store' Page({ // 页面加载设置store绑定成员信息 onLoad:function(){ this.storeBindings=createStoreBindings(this,{ store, fields:['num1','num2','sum12'], // 共享字段 actions:['updateNum1'] // 共享方法 }) }, // 页面卸载时清理处理 onUnload:function(){ this.storeBingds=this.destroyStoreBindings() }, // 按钮点击时触发的方法 addNum(e){ // 执行修改num1方法并按照指定步长step进行相加 this.updateNum1(e.target.dataset.step) } })
component中绑定store对象(指定behavior:storeBindingsBehavior,设置storeBindings)
// 导入behavior对象:storeBindingsBehavior import {storeBindingsBehavior} from 'mobx-miniprogram-bindings' // 导入自定义store对象实例 import {store} from '../store/store' Component({ // 设置behavior数组 behaviors:[storeBindingsBehavior], // 映射参数绑定,storeBindings属性,按照page对象格式添加,fields actions为子节点对象,key-value形式添加内容.key为组件信息,value为store信息 storeBindings:{ store, fields:{ // 组件字段:store字段 num:()=>store.num //方式一 //num:(store)=>store.num // 方式二 // num:'num' .// 方式三 }, // 映射方法绑定 actions:{ // 组件方法:store方法 updateNum:'updateNum' } } })
=>为es6语法用作函数简写,参考如下示例:
// 无参数 var f = () => 5; // 等同于 var f = function () { return 5 }; =========================================== // 一个参数 var f = a = > b //等同于 var f = function(a){ return b; } ==================================================== //多个形参 var sum = (num1, num2) => num1 + num2; // 等同于 var sum = function(num1, num2) { return num1 + num2; };
const { data } = await login(xxx)这是取login返回结果中的data属性
const {data:res} = await login(xxx)这是将data重命名为res
vue官方文档地址: https://vuejs.bootcss.com/guide/
数据绑定缩写:
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
点击事件缩写:
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
导入格式:
import xxx from xxx路径
xxx表示导入内容的变量名,不仅仅支持导入js文件.
xxx路径 指的的是文件的相对路径.
文件相对路径说明:
./表示当前文件
…/表示上级文件.
@:表示以根目录的方式定义相对路径.
@导入示例如下:
导入方法,以下导入时间解析方法为例说明:
工具类tool.js
//时间间隔函数 export function timeInterval(timesData) { //如果时间格式是正确的,那下面这一步转化时间格式就可以不用了 var dateBegin = timesData;//将-转化为/,使用new Date var dateEnd = new Date();//获取当前时间 var dateDiff = Math.abs( dateEnd.getTime() - dateBegin ); //时间差的毫秒数 var yearDiff = Math.floor(dateDiff / (24 * 3600 * 1000*365)); var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数 var leave1 = dateDiff % (24 * 3600 * 1000) //计算天数后剩余的毫秒数 var hours = Math.floor(leave1 / (3600 * 1000))//计算出小时数 //计算相差分钟数 var leave2 = leave1 % (3600 * 1000) //计算小时数后剩余的毫秒数 var minutes = Math.floor(leave2 / (60 * 1000))//计算相差分钟数 //计算相差秒数 var leave3 = leave2 % (60 * 1000) //计算分钟数后剩余的毫秒数 var seconds = Math.round(leave3 / 1000); var timesString = ''; if (yearDiff!=0){ timesString = yearDiff + '年前'; } else if (yearDiff == 0 && dayDiff != 0) { timesString = dayDiff + '天前'; } else if (dayDiff == 0 && hours != 0) { timesString = hours + '小时前'; } else if (hours == 0 && minutes != 0) { timesString = minutes + '分钟前'; } else if (minutes == 0 && seconds<60){ timesString = '刚刚'; } return timesString } // 日期格式化 export function parseTime(time, pattern) { if (arguments.length === 0 || !time) { return null } const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' let date if (typeof time === 'object') { date = time } else { if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { time = parseInt(time) } else if (typeof time === 'string') { time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), ''); } if ((typeof time === 'number') && (time.toString().length === 10)) { time = time * 1000 } date = new Date(time) } const formatObj = { y: date.getFullYear(), m: date.getMonth() + 1, d: date.getDate(), h: date.getHours(), i: date.getMinutes(), s: date.getSeconds(), a: date.getDay() } const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { let value = formatObj[key] // Note: getDay() returns 0 on Sunday if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } if (result.length > 0 && value < 10) { value = '0' + value } return value || 0 }) return time_str }
script中导入parseTime方法:
<script> // 导入工具类,使用时间解析方法 import {parseTime} from '@/utils/tool.js'; export default { data() { return { }; }, methods:{ getNewsDetail(cid,id){ uni.request({ url:"https://ku.qingnian8.com/dataApi/news/detail.php?cid="+cid+"&id="+id, success: (res) => { if(res.statusCode==200){ this.newsDetail=res.data; // 时间戳转化为日期格式 this.newsDetail.posttime = parseTime(this.newsDetail.posttime, '{y}-{m}-{d} {h}:{i}:{s}'); }) } } }) } } } </script>
全局变量以及全局方法有以下几种方式:
1.main.js中通过Vue.prototype设置
2.模块化自定义js文件定义
3.APP.vue中定义
下面依次介绍
vue2中:
//main.js
Vue.prototype.$message = {
name:'你好啊'
};
//页面取值
this.$message
vue3中:
//main.js
const app=createApp(App)
app.config.globalProperties.$message = {
name:'你好啊'
};
//页面取值
import { getCurrentInstance } from "vue";
export default {
setup() {
let { proxy } =getCurrentInstance() //getCurrentInstance()用于获取当前组件的上下文
console.log(proxy.$message);
}
}
补充另一种全局变量定义方式,使用模块化定义.然后从调用文件中进行引入,比如说定义全局的服务端路径.可以直接从js中定义,示例:
http.api.js中:
export default{
serverUrl:"http://127.0.0.1:8080",
uploadUrl:"/uploadImg"
}
// 定义图片上传路径方式2
//export const uploadUrl ="/uploadImg"
http拦截器中使用全局服务端路径:
// 导入
import httpConfig from "../common/http.api.js"
// 此vm参数为页面的实例,可以通过它引用vuex中的变量
module.exports = (vm) => {
// 初始化请求配置
uni.$u.http.setConfig((config) => {
// 服务端路径
config.baseURL = httpConfig.serverUrl;
return config
})
}
mine.vue中文件上传使用script中:
import httpConfig from "../../common/http.api.js"; import { findUserInfo, updateUserInfo //uploadUrl // 方式2,上传图片接口名定义 } from '../../common/http.api.js'; export default { uploadImg(filePath){ uni.uploadFile({ // url: 'http://127.0.0.1:8080/aliyun/uploadImg', //仅为示例,非真实的接口地址 url: httpConfig.serverUrl+httpConfig.uploadUrl, // 方式2 //url: httpConfig.serverUrl+uploadUrl, filePath: filePath, name: 'multipartFile', success: (uploadFileRes) => { console.log("上传返回信息:"+JSON.stringify(uploadFileRes.data)) let responseInfo=JSON.parse(uploadFileRes.data) if(responseInfo.code == 200){ this.userImg=responseInfo.data, console.log("图片上传地址:"+this.userImg) this.model1.userInfo.userImg=this.userImg }else{ uni.showToast({ title:"图片上传失败,请重试!", duration:3000 }) } } }) } }
再补充一种方式APP.vue中设置:
<script>
// import {findShopList} from '@/api/api.js'
export default {
globalData:{
latitude:'',
longitude:''
}
}
</script>
使用方法:
getApp().globalData.latitude
vue中数据类型为基础数据类型(字符串/数字/布尔类型)和非基础类型.
<template> <view> <view>字符串类型:{{value1}}</view> <view>数字类型:{{value2}}</view> <view>布尔类型:{{value3}}</view> <view>数组类型:{{value4}}</view> <view>对象类型:{{value5}}</view> <view>获取对象属性:{{value5.name}}</view> <view>{{}}</view> </view> </template> <script> export default { data() { return { value1:"你好", value2:20, value3:true, value4:[1,2,3,4], value5:{ "name":"张三", "age":20 } } }, methods: { } } </script>
展示效果:
两个都是用来控制组件是否显示.v-if经常与v-else或是v-else-if使用.注意不能分开,否则会报错.
<template> <view> <view v-if="state">hello nuiapp!</view> <view v-else>hello 小程序</view> ========================================= <view v-if="gender == 1">男</view> <view v-else-if="gender == 2">女</view> <view v-else>未知</view> ========================================= <view v-show="state">hello nuiapp!</view> <view v-show="!state">hello 小程序</view> </view> </template> <script> export default { data() { return { state:false ,// 控制显示hello uniapp还是显示hello 小程序 gender:3 // 1.男;2.女;3.未知 } }, methods: { } } </script>
v-if 和 v-show 区别
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做,直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多,不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换,来控制元素的显示和隐藏。
根据应用场景选择
v-if 有更高的切换开销,如果在运行时条件很少改变,则使用 v-if 较好。 v-show
有更高的初始渲染开销。如果需要非常频繁地切换,则使用 v-show 较好。
v-html的作用是更新元素的innerHTML,对于data中定义的数据为html标签时,使用{{}}进行解析时只能文本输出,如果想按照标签解析就可以使用v-html.
<template> <view> <view >{{html}}</view> <view v-html="html"></view> </view> </template> <script> export default { data() { return { html:'<h2>uniapp入门</h2>' } }, methods: { } } </script>
实现效果:
v-bind的作用是动态赋值,一般是将data中定义的变量值赋值给组件的属性.data中变量动态变化实现组件属性动态变化.
下面示例显示图片信息,地址显示问题可以在src中定义,也可以从data中的imgUrl变量中进行取值,:src是v-bind:src的简化写法.
<template> <view> <image src="../../static/logo.png"></image> <image :src="imgUrl"></image> <image v-bind:src="imgUrl"></image> </view> </template> <script> export default { data() { return { imgUrl:"../../static/logo.png" } } } </script>
v-model 指令可以在表单 input、textarea 及 select 元素上创建双向数据绑定.按照以下案例来讲,文本框中输入内容,上面显示的内容就会变化;data中对content进行内容修改,input中显示的内容也会变化.
<template> <view> <view>显示内容:{{content}}</view> <view> 输入内容:<input class="input_class" v-model="content"/> </view> </view> </template> <script> export default { data() { return { content:"显示内容" } } } </script> <style lang="scss"> .input_class{ border: 1rpx solid gray; } </style>
效果展示:
ref 写在标签上时:this.$refs.ipt 获取的是添加了ref="ipt"标签对应的dom元素
ref 写在组件上时:this.$refs[‘component’] 获取到的是添加了ref="component"属性的这个组件
<template>
//给标签使用
<input type="text" ref="ipt"/>
//给组件使用
<comp-detail ref="component"></comp-detail>
<button @click="confirm">确定</button>
</template>
methods:{
confirm(){
console.log(this.$refs.ipt.value) //打印出输入框中的value值
this.$refs['component'].init() //调用组件comp-detail中的init()方法
}
}
js中存在多个方法,执行顺序是同步执行,但是并不一定是按照顺序从上往下执行,如果想指定多个方法的执行顺序,可以使用async与await异步操作,async一般用于方法名前,要指定先执行的请求服务端方法名前添加await
a = a || {}
表示的意思是如果a为null或是undefined就定义为空对象,否则就是a
config:{ // config对象内容
header:"",
custom:{
auth:""
}
}
// 对于多次获取对象属性的情况,如果其中有一个属性为null就会报undefined提示,可以用?.的方式进行调用,如果为null或是undefined则停止调用,最终结果不为null或是undefined则返回布尔值true
config?.custom?.auth
display:flex表示横向排列.
说明文档:https://www.runoob.com/cssref/css3-pr-flex.html
容器横向排列,效果:
类似的布局可以看成两个view容器,保持两个view容器进行横向排列即可.注意设置样式的时候是从这两个容器的父容器中设置:
display: flex;
scss语法:
官方文档:https://sass.bootcss.com/guide
轮播图设置swipe组件与image组件大小同步view.
页面:
<view class="swiper_view">
<swiper indicator-dots=true autoplay=true interval=3000 acceleration=true >
<swiper-item v-for="swiperItem in swiperList" :key="swiperItem.image_src">
<image :src=swiperItem.image_src></image>
</swiper-item>
</swiper>
</view>
样式:
<style lang="scss">
swiper {
height: 330rpx;
.swiper-item,
image {
width: 100%;
height: 100%;
}
}
</style>
justify-content: space-around;
参考文档:
https://www.runoob.com/cssref/css3-pr-justify-content.html
上个案例中图片分类间距过小如何调整问题.
调整内边距:
margin: 15px;
调整之后:
如果想给view 标签设置高度宽度以及背景颜色,直接赋值:
<view style="height: 60px;width: 60px;background: yellow;"></view>
数据绑定参数赋值(注意多项属性需要逗号进行分割不是分号):
<view :style="{height: heightValue,width: widthValue,background:backgroundValue}"></view>
script中:
<script>
export default {
data() {
return {
heightValue: "60px",
widthValue: "60px",
backgroundValue: 'green',
}
},
methods: {
}
}
</script>
补充,如果一个标签中仅对其中一个样式进行动态绑定,按照下面操作:
<view :style="'background-color:' + (Expression ? '#FFFFFF' : '#000000')"></view>
image组件默认大小:300px*240px.
如果想调整图片内容占据image标签的多少,可以设置mode属性.
mode常用值:
aspectFit:保持横向的长边完全显示,纵向进行缩放;
纵向进行缩放.
aspectFill:保持纵向宽边完全显示出来,横向进行缩放;
横向进行缩放,对比原图部分内容不显示.其余属性参考链接:
https://uniapp.dcloud.net.cn/component/image.html#image
一般使用默认mode:scaleToFill,不对图片进行压缩,只需要设置image的长宽可父元素view大小一致即可.
<view class="item">
<image src="../../static/logo.png"></image>
<view>uniapp实战</view>
<view>免费</view>
</view>
.item{
width: 40vw;
height: 55vw;
display: flex;
flex-direction: column;
margin: 2rpx;
}
.item image{ // 图片默认scaleToFill,填充满image
width: 100%;
}
display:flex;
flex-wrap: wrap;
参考链接:
https://www.runoob.com/cssref/css3-pr-flex-wrap.html
案例说明:列表内容中默认选中第一个,并添加背景颜色红色
<block v-for="(cateItem,cateIndex) in cateList" :key="cateIndex">
<view :class="['left-scroll-view-item',cateIndex==firstActive ? 'firstActive': '']" style="height:20px;width:80px;" @click="changeActive(cateIndex)">{{cateItem.cat_name}}
</view>
</block>
.firstActive {
// 拥有firstActive的标签背景色为红色
background-color: red;
}
changeActive(cateIndex){
// 切换操作将firstActive设置为当前选择项索引
this.firstActive=cateIndex;
}
呈现效果:
设置默认选中索引为firstActive,默认设置为0,进行切换,将firstActive设置为选择项的索引.:class="['left-scroll-view-item',cateIndex==firstActive ? 'firstActive': '']"
表示动态绑定,表示当前view如果被选中,会有两个class类型: left-scroll-view-item
和firstActive
,注意对class进行动态绑定时class名为字符串形式.
样式绑定文档地址:
https://www.runoob.com/vue3/vue3-class-bind.html
text-align,三种文本对齐方式:
https://www.runoob.com/cssref/pr-text-text-align.html
常用的居中方式参考:
display: flex;
justify-content: space-around;
align-items:center;
另外设置文本在盒子按照上下居中显示可以设置line-height属性等于盒子高度,呈现的效果就是上下居中.align-items:center是左右方向进行居中;
注意:text-align不仅仅只对文本元素起到水平方向对齐方式设置,对于其他元素也会起到水平方法对齐的作用,比如h1标签、button标签。
view中文本居中处理(text-align: center+line-height:父元素高度):
<view class="itme">2</view>
.itme{
background-color: yellow;
height: 200px;
width: 200px;
text-align: center;
line-height: 200px;
}
效果如下:
或是按照下面这种实现(用justify-content和align-items):
.itme{
background-color: yellow;
height: 200px;
width: 200px;
display: flex;
justify-content: center;
align-items: center;
}
margin-top:设置距离顶部的距离
margin-left:设置距离左边距离;
给view设置高度、宽度、背景颜色、边框多种样式
最简单设置方式:
<view class="sizeClass backgroundClass broderClass" ></view>
样式:
<style lang="scss">
// 宽度、高度
.sizeClass{
height: 40px;
width: 40px;
}
// 背景颜色
.backgroundClass{
background: red;
}
// 边框
.broderClass{
border: 5px solid yellow
}
</style>
动态绑定之对象方式设置:
<view class="sizeClass" :class="{'backgroundClass':true,'broderClass':true}"></view>
</view>
一般在data中设置状态值:true表示样式显示,false表示样式不显示.
动态绑定之数组设置方式:
<view class="sizeClass" :class="[backgroundClass,broderClass]"></view>
</view>
script中:
<script>
export default {
data() {
return {
// 数组方式绑定对应样式名
backgroundClass:'backgroundClass',
broderClass:'broderClass'
}
},
methods: {
}
}
</script>
显示内容:
以下示例也展示v-for循环数据并点击跳转聊天窗口显示最上面的用户名.函数传参实现见代码
聊天列表:
<template> <view> <uni-list> <uni-list :border="true"> <!-- 显示圆形头像 --> <uni-list-chat :avatar-circle="true" v-for="chatItem in wxChatList" :key="chatItem.id" :title="chatItem.userName" :avatar="chatItem.url" :note="chatItem.content" :time="chatItem.createTime" :clickable="true" @click="toChat(chatItem.userName)"></uni-list-chat> </uni-list> </uni-list> </view> </template> <script> export default { data() { return { wxChatList: [{ id:1, userName: '小花', url: 'https://web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png', content:'今晚吃什么', createTime:'2022-12-25 18:36' }, { id:2, userName: '小黄', url: 'https://web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png', content:'明天去哪?', createTime:'2023-08-25 08:40' }] } }, methods: { toChat(userName){ uni.navigateTo({ url: '../chat/chat?title'+userName }) }, toChat2:function(){ uni.navigateTo({ url: '../chat/chat?title=APP' }) } } } </script>
聊天窗口:
<template> <view> </view> </template> <script> export default { data() { return { }; }, // 页面展示时记载聊天对象标题 onLoad: function (obj) { console.log(obj); uni.setNavigationBarTitle({ title:obj.title }); } } </script>
注意事项:
onload方法中如果想调用methods中的方法,不能直接写方法名,需要使用this.方法名,否者会显示方法名未定义;另外onload可以用来获取上个页面传递过来的参数.
script标签内容:
<script> export default { data() { return { }; }, onLoad(e) { this.getCommentList(e.id) }, methods:{ getCommentList(newsId){ uni.request({ url:"http://127.0.0.1:8090/api/comment/listAll/2/"+newsId, method:"POST", data:{ "pageIndex": 1, "pageSorts": [ { "column": "", "asc": true } ], "pageSize": 10, "keyword": "" }, success: (res) => { if(res.data.code == 200){ this.commentList=res.data.data.records }else{ uni.showToast({ title:"数据获取异常!", icon:'error' }) } } }) } } } </script>
前一个页面传参设置:
点击事件实现逻辑:
methods:{
// 跳转详情
goToDetail(e){
// e表示传递请求方法中传递的参数
uni.navigateTo({
url:"../news_detail/news_detail?id="+e
})
}
}
scss的作用:支持css样式嵌套;支持uni.scss文件中全局样式定义;
样式嵌套的实现方式:
<template> <view> <!-- scss的使用 --> <view class="outClass"> <h3>scss的使用</h3> </view> </view> </template> <script> export default { data() { return { } }, methods: { } } </script> <style lang="scss"> .outClass{ height:200rpx; width:200rpx; background-color: green; h3 { padding-left: 20px; } } </style>
全局样式的使用:
<template> <view> <!-- scss的使用 --> <view class="outClass"> <h3>scss的使用</h3> </view> </view> </template> <script> export default { data() { return { } }, methods: { } } </script> <style lang="scss"> .outClass{ height:200rpx; width:200rpx; background-color: green; h3 { padding-left: 20px; // 全局样式 background-color: $uni-color-custom; } } </style>
style标签中指定scss后,项目根目录下面会生成uni.scss文件,里面默认定义了很多样式,可以直接在各个页面使用,当然也可以进行自定义全局样式,上面的$uni-color-custom
就是自定义样式.
展示内容如下:
view类似于div属于快标签,text类似于span标签,相当于行级标签.区别在于前者会换行,后者不会换行.
<template>
<view>
<!-- view与text区别 -->
<view class="view1">view块标签一</view>
<view class="view2">view块标签二</view>
<view>========================================================</view>
<text>text标签一</text>
<text>text标签二</text>
</view>
</template>
展示效果:
实现点击选中的文字显示绿色
<template> <view> <view class="viewClass"> <view class="itemClass" @click="selectItem(index)" v-for="(item,index) in contenList" :key="index" :class="isActive == index ? 'activeClass' : ''" >{{item.content}} </view> </view> </view> </template> <script> export default { data() { return { contenList:[ { id:1, content:"首页" }, { id:2, content:"分类" }, { id:3, content:"练习" }, { id:4, content:"我的" } ], isActive:0 // 使用索引index进行创建 } }, methods:{ selectItem(e){ console.log(e), this.isActive=e } } } </script> <style lang="scss"> .viewClass{ width: 100%; height: 80rpx; display: flex; justify-content: space-around; background-color: gray; align-items:center; .itemClass{ width: 25%; text-align: center; line-height: 80rpx; &.activeClass{ background-color: green; } } } </style>
注意表单提交时,需要指定form组件内标签的name属性,否则提交的时候表单内容不会获取到.
<template> <view class="out"> <form @submit="submitForm" @reset="restForm"> <view> <input type="text" placeholder="请输入用户名" name="userName"/> </view> <view> <input type="text" placeholder="请输入密码" name="password"/> </view> <view> <radio-group @change="changeValue" name="gender"> <radio value="1" checked>男</radio> <radio value="2">女</radio> </radio-group> </view> <view> <picker @change="changPicker" :range="educationList" name="education" >学历:{{educationInfo}}</picker> </view> <button type="primary" form-type="submit" @click="submitInfo">提交</button> <button type="warn" form-type="reset">重置</button> </form> </view> </template> <script> export default { data() { return{ educationList:['小学','初中','高中','大学'], educationInfo:"" // 显示学历信息 } }, methods: { submitForm(e){ // 表单提交触发逻辑,对应form组件@submit console.log(e.detail.value) }, restForm(e){ // 重置表单信息 console.log("清空表单信息") }, changeValue(e){ // 单选框切换时触发 console.log(e.detail.value) }, changPicker(e){ // 下拉框切换时触发 this.educationInfo=this.educationList[e.detail.value] } } } </script> <style lang="scss"> .out{ padding: 10rpx; } </style>
页面显示效果如下:
注意:pick标签实现下拉选择效果与uni.showActionSheet效果基本相同.
主要作用是可以对属性值进行单独处理,methods方也可以实现,区别在于computed性能开销小.下面示例实现输入内容之后将字母变成大写的实现.
注意computed中写法类似于函数,调用的时候直接写函数名即可,不带括号.
<template> <view> <input placeholder="输入内容" v-model="content"/> </view> <view>显示输入内容:{{content}}</view> <view>显示大写之后的内容:{{upperContent}}</view> </template> <script> export default { computed:{ upperContent(){ return this.content.toUpperCase() } }, data() { return{ content:'' } }, methods: { } } </script> <style lang="scss"> </style>
实现效果:
自定义组件中添加自定义属性.
自定义组件:
<template> <view class="my-componet-box"> <view class="view1">{{title}}</view> <view class="view2">{{subTitle}}</view> </view> </template> <script> export default { name:"my-componet", data() { return { title:'主标题', subTitle:"副标题" }; }, props:{ title: { type: String, default: "主标题", required: false }, subTitle:{ type: String, default: "副标题", required: false, } } } </script> <style lang="scss"> .my-componet-box{ width: 400rpx; height: 200rpx; background-color: green; .view1{ font-size: 60rpx; } } </style>
tabbar首页和列表页引入,其中列表页主标题以及副标题均保持默认值,首页自定义属性指定默认值.
首页:
<template> <view class="content"> <my-componet title="首页主标题" subTitle="首页副标题"></my-componet> <image class="logo" src="/static/logo.png"></image> <view class="text-area"> <text class="title">{{title}}</text> </view> </view> </template> <script> export default { data() { return { title: 'Hello' } }, onLoad() { }, methods: { } } </script> <style> .content { display: flex; flex-direction: column; align-items: center; justify-content: center; } .logo { height: 200rpx; width: 200rpx; margin-top: 200rpx; margin-left: auto; margin-right: auto; margin-bottom: 50rpx; } .text-area { display: flex; justify-content: center; } .title { font-size: 36rpx; color: #8f8f94; } </style>
列表页:
<template> <view> <vie>列表页面</vie> <my-componet ></my-componet> </view> </template> <script> export default { data() { return { }; } } </script> <style lang="scss"> </style>
展示效果:
以上是父组件引用子组件,通过修改父组件data中变量信息修改子组件属性值.下面讲一下子组件实现传值给父组件.
用案例说明一下如何实现:平常会将常用的文本输入封装成组件给各个页面调用,这里就涉及到子组件文本输入内容传值到父组件问题.下面介绍如何子组件向父组件传值.
自定义子组件:
<template> <view> <input placeholder="请输入内容..." @input="sendData"/> </view> </template> <script> export default { name:"my-componet-2", data() { return { }; }, methods:{ sendData(e){ console.log(e.detail.value), this.$emit('myEvent',e.detail.value), this.$emit('myEvent',{value:e.detail.value}) // 支持传递对象或数组 } } } </script> <style lang="scss"> </style>
home页面引用子组件:
<template> <view> <vie>my page</vie> <my-componet-2 @myEvent="showData"></my-componet-2> </view> </template> <script> export default { data() { return { }; }, methods:{ showData(e){ console.log(e) } } } </script> <style lang="scss"> </style>
实现效果:
文本框中输入8,子组件打印数据之后,父组件通过自定义事件进行获取数据,另外子组件向父组件传递值时支持对象或数组格式.
总结一下实现过程:
子组件数据变化之后需要使用this.$emit进行注册事件,通过事件进行传值;父组件在子组件中使用自定义事件进行获取数据.
sync修饰符
可以理解为父子组件实现子组件属性的双向绑定,使用sync写法上会简单(语法糖),先看不使用sync的实现.
子组件中input输入框变化之后同步到父组件显示,父组件更改data中内容,子组件属性值同步变化.
自定义组件:
父元素引用自定义组件子元素时不能在子组件中直接使用click事件,需要加native修饰符.上面自定义组件my-componet在learn页面中引入,添加点击事件如果不加native是不生效的.只有添加native修饰符才会触发点击事件,learn页面内容如下:
<template> <view> <view @click="toPage">点击我跳转页面</view> --> <my-componet @click.native="clickComponent"></my-componet> </view> </template> <script> export default { data() { return { } }, methods:{ clickComponent(){ console.log("点击子组件方法生效!") } } } </script> <style lang="scss"> </style>
页面显示:
另外看下自定义组件内部中如何直接添加事件:
https://uniapp.dcloud.net.cn/tutorial/vue-components.html#将原生事件绑定到组件
<template> <view> <input placeholder="请输入内容..." @input="sendData" /> </view> <view>子组件属性值content:{{content}}</view> </template> <script> export default { name:"my-componet-2", data() { return { content:"子组件属性值" }; }, methods:{ sendData(e){ console.log(e.detail.value), // this.$emit('myEvent',e.detail.value) this.$emit('update:content',e.detail.value) } }, props:{ content:{ type:String, default: "子组件默认内容", } } } </script> <style lang="scss"> </style>
父组件:
<template> <view> <vie>my page</vie> <div>父子组件对props中content属性实现双向绑定显示子组件属性值:{{content}}</div> <!-- <my-componet-2 :content="content" @myEvent="showData"></my-componet-2> --> <my-componet-2 :content="content" @update:content="showData"></my-componet-2> </view> </template> <script> export default { data() { return { content:'456' }; }, methods:{ showData(e){ // console.log(e) this.content=e } } } </script> <style lang="scss"> </style>
sync修饰符写法:
自定义组件:
父组件:
常见实现方式有两种,一种是navigator组件,另一种是方法中执行uni.navigateTo({}),当然底层都是使用的后者,这里面需要主要的是要转的页面是非tabbar页面,另外请求路径可以是相对路径也可以是绝对路径.关于页面请求参数获取可以使用onload方法进行获取,直接从onload方法参数就是路径传递参数.另外getCurrentPages()方法可以获取页面栈对象信息.下面的示例介绍如何从练习页面跳转到非tabbar的聊天页面.
练习页面:
<template> <view> <!-- navigator组件使用相对路径进行跳转 --> <!-- <navigator url="../chat/chat?userName='jack'">navigator组件跳转</navigator> --> <!-- navigator组件使用绝对路径进行跳转 --> <navigator url="/pages/chat/chat?userName='jack'">navigator组件跳转</navigator> <view @click="toPage">点击我跳转页面</view> </view> </template> <script> export default { data() { return { } }, methods:{ toPage(){ uni.navigateTo({ // 绝对路径跳转 // url:"/pages/chat/chat?userName='rose'&age=18" // 相对路径跳转 url:"../chat/chat?userName='rose'&age=18" }) } } } </script> <style lang="scss"> </style>
聊天页面:
<template> <view> <view>聊天页面</view> </view> </template> <script> export default { data() { return { }; }, onLoad(obj) { // 获取页面请求参数信息 console.log(obj), // getCurrentPages()获取页面栈信息 console.log((getCurrentPages())) } } </script> <style lang="scss"> </style>
跳转之后实现效果:
注意:使用navigator组件不生效可能原因请检查跳转页面否在page.json中注册,对于存在于subpages中的页面也需要在pages中注册.
补充:创建subpages方法:
项目根目录中创建subpages文件夹.pages.json中添加subpages配置信息:
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages { "path": "pages/webView/webView", "style": { "navigationBarTitleText": "webview", "enablePullDownRefresh": false } }, { "path": "subpages/news_detail/news_detail", "style": { "navigationBarTitleText": "", "enablePullDownRefresh": false } } ], "subPackages": [{ "root": "subpages", "pages": [ // 此处为pages注册的子页面路径,此处省略子页面的样式配置 "news_detail/news_detail" ] }]
常用交互:
uni.showToast 弹出对话框,支持定时以及加载中效果展示,支持添加蒙版,加载中无法点击其他内容.
uni.hideToast 隐藏对话框
uni.showLoading 显示加载中,无定时,需要使用隐藏api才能停止.
uni.hideLoading 隐藏加载中
uni.showModal 显示对话框,支持输入文本.下面案例介绍点击图片弹出对话框.
uni.showActionSheet 从底部弹出下拉选项.
<template> <view> <view> <image src="../../static/logo.png" @click="showModel"></image> </view> </view> </template> <script> export default { data() { return { }; }, methods:{ // 点击图片显示弹窗 showToast(){ uni.showToast({ title:"操作成功", // 提示信息 icon:"success", // 显示图标 duration:3000 ,// 显示时长 mask: true // 是否显示透明模板,true时页面点击任意区域无效果 }) }, // 点击区域显示样式 changeStyle(){ this.isActive=!this.isActive }, showModel(){ uni.showModal({ title:"是否输入手机号?", editable:"请输入手机号", // success:function(e){ // if(e.confirm){ // console.log("操作成功,输入手机号:"+e.content) // }else{ // console.log("禁止获取手机号!") // } // } success: (res) => { if(res.confirm){ console.log("操作成功a,输入手机号:"+res.content) }else{ console.log("禁止获取手机号!") } } }) } } } </script> <style lang="scss"> .viewClass{ width: 200rpx; height: 500rpx; background-color: red; } </style>
展示效果:
dotted solid double dashed
<template> <view> <view>聊天页面</view> <view class="out"> <view class="viewClass1">border常用样式:带点边框</view> <view class="viewClass2">border常用样式:实体边框</view> <view class="viewClass3">border常用样式:虚线边框</view> <view class="viewClass4">border常用样式:双层边框</view> </view> </view> </template> <script> export default { data() { return { }; } } </script> <style lang="scss"> .out{ .viewClass1{ border: dotted; // 带点边框 } .viewClass2{ border: solid; // 实体边框 } .viewClass3{ border: dashed; // 虚线边框 } .viewClass4{ border: double; // 双层边框 } } </style>
效果如下:
padding常用属性说明:
padding解析顺序为顺时针(上右下左),如果不足4个则参考以下内容:
padding:10px 5px 15px 20px; 上填充是 10px 右填充是 5px 下填充是 15px 左填充是 20px
padding:10px 5px 15px; 上填充是 10px 右填充和左填充是 5px 下填充是 15px
padding:10px 5px; 上填充和下填充是 10px 右填充和左填充是 5px
padding:10px; 所有四个填充都是 10px
使用示例:
<template> <view> <view>聊天页面</view> <view class="out"> <view class="inner">内容</view> </view> </view> </template> <script> export default { data() { return { }; } } </script> <style lang="scss"> .out{ width: 200rpx; height: 200rpx; border: 2rpx solid gray; .inner{ // padding: 80rpx; // 上 右 下 左都是80rpx // padding: 80rpx 40rpx; // 上 下都是80rpx,左右都是40rpx padding: 80rpx 40rpx 20rpx; // 上80rpx,左右都是40rpx 下20rpx } }
onLoad(){
// 同步设置缓存数据,value支持字符串对象或是集合以及其他数据类型 uni.setStorageSync("userName","jack"),
uni.setStorageSync("cotent",{"userName":"rose","age":20}),
console.log(uni.getStorageSync("userName")),
console.log(uni.getStorageSync("cotent"))
// 删除指定key的数据缓存
uni.removeStorageSync("userName")
// 删除所有的缓存信息
uni.clearStorageSync()
}
控制台打印获取缓存数据:
本地缓存数据:
注意初始化方法是onLoad不是onload方法;
注意uni.getStorageInfoSync()
与uni.getStorageSync(KEY)
区别,前者是获取缓存的应用信息,后者是获取缓存指定key的具体内容.前者获取的内容如下:
keys":["token"],"currentSize":1,"limitSize":10240
缓存中添加对象与从缓存中获取对象信息
保存:
保存:
let items = JSON.stringify(数组或者对象);
uni.setStorageSync("userInfo" , items);
取出:
var data = uni.getStorageSync("userInfo" );
var items = JSON.parse(data)
水平显示的文字不换行:
white-space:nowrap
行号line-height与字体大小font-size区别:
行高大小等于父元素高度时,文字垂直居中展示;
行号等于字体大小+上下间距.
水平排列的文字想间隔一定距离可以使用
padding:0 30rpx
弹性盒子:
display:flex会构建弹性盒子,一般用于父元素,
所有弹性盒模型对象的子元素都有相同的长度
flex:1;
子元素中常用的属性有以下几个:
flex-direction将弹性盒子子元素按照行或是列(flex-direction: column
)的方式排列;
justify-content将盒子均匀分布,常用以下两个:
ustify-content: space-between; /* 均匀排列每个元素
首个元素放置于起点,末尾元素放置于终点 */
justify-content: space-around; /* 均匀排列每个元素
justify-content: center; // 居中
align-items 设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式。比如设置文本在view中居中显示可以使用:
display: flex;
align-items: center;
图片在指定view中完全显示方法:设置好图片父元素的宽和高,然后设置图片的宽和高都是100%.然后设置图片的mode模式为aspectFill(image组件)
文字一行展示:display: inline-block;
字体加粗:font-weight: bold;
使用position属性设置方式:
position:fixed;
buttom:0;
注意:多个组件进行重叠展示可以使用position:relative或是absolute;
absolute相对位置定位,是基于父组件,注意是基于已定位的组件,如果父组件没有定位,则是按照整个页面定位处理;为保证子组件在已定位的父组件定位absolute有效果,可以将不存在position的父组件设置position为relative.
fixed是基于浏览器窗口的固定位置;
参考: https://www.runoob.com/cssref/pr-class-position.html
重叠顺序可以通过z-index属性指定。
底部距离不生效注意检查一下拼写:bottom,非button
可以使用margin:auto.对于padding-left不生效,可以考虑使用margin:auto.示例:
如下view保证水平居中显示:
.recommend_news_class{
margin: auto;
}
另外也可以考虑添加父view(需要保证父宽度为100%),设置align-items: center;
补充:可以使用position:absolute,相对于父元素移动指定距离;
父元素{
display: flex;
flex-wrap: wrap;
子元素{
padding-left: 15rpx;
}
}
类似实现效果:
flex支持弹性布局,常用属性详细教程:
https://www.runoob.com/w3cnote/flex-grammar.html
flex六个常用属性:
flex-direction:决定元素按照行或是列排列,支持行或是列反向排列;
justify-content:决定元素在水平方向上排列方式;
flex-wrap:一般用来按照水平排列支持换行或不换行或反向换行;
align-items:用来处理多个垂直元素在水平方向的对齐排列;
align-content:决定多个水平元素在水平方向上的排列方式;
background-color表示设置view的背景颜色;
color表示设置字体颜色,view中有字体使用color表示设置字体颜色;类似于以下:
background:支持添加背景图
参考地址:
https://www.runoob.com/cssref/css3-pr-background.html
设置页面的背景图:
<template>
<view class="index_class">
<!-- 背景图 -->
<image class="bk_img_class" src="../../static/index/index_bg.png"></image>
</view>
</template>
<style lang="scss">
.bk_img_class {
position:fixed;
top:0;
width:100%;
height:100%;
}
</style>
// mine为最外层view上面添加下面内容
uni-page-body,page {
height:100%
}
.mine{
width: 100%;
height: 100%;
background-color: #4b76e5;
}
看下下面的头像昵称性别如何间隔一定距离显示,并且需要左对齐.效果如下:
左对齐,最外层view中设置justify-content: flex-start;
,text与右边的image外边都包裹一个view,对view设置padding-left: 20rpx;
,
(注意:justify-content: flex-start不生效可以看下使用该样式的父子组件是否指定width宽度,没有指定width宽度会导致组件失效.)
代码如下:
<view class="user_class"> <my-u-avatar src="/static/logo.png" size="45"></my-u-avatar> <view class="nickName"> <text>小米</text> </view> <view class="gender" > <image :src="currentGender == 2 ? 'https://oss.haokeruanjian.top/drift/img/gender_woman.png' : 'https://oss.haokeruanjian.top/drift/img/gender_man.png'"> </image> </view> </view> // 样式 .user_class { display: flex; justify-content: flex-start; align-items: center; padding-top: 5rpx; // padding-left: 15rpx; height: 20%; width: 100%; .nickName{ padding-left: 20rpx; } .gender{ padding-left: 20rpx; image { height: 40rpx; width: 40rpx; } } }
不能按照以下方式添加padding-left,否则样式会显示成这种:
text{
padding-left: 20rpx;
}
image {
padding-right: 20rpx;
height: 40rpx;
width: 40rpx;
}
padding-left表示在所标注的元素样式大小基础上相对于本身想做偏移一定的像素.所以需要从外边包裹一个view,对view进行padding-left以制造出有间隔的样式.
实现效果如图:
使用position:absolute;基于父元素定位不生效,可以考虑使用position:relative,相关代码如下:
<view class=".img_view" v-for="(img,index) in imgList" :key="index"> <image :src="img" mode="scaleToFill"></image> <image class="delete_img" src="https://oss.haokeruanjian.top/drift/img/delete.png" @click="deleteImg()"></image> </view> script中: .img_view{ height: 80px; width: 80px; // display: flex; image{ height: 80px; width: 80px; } .delete_img{ position:relative; left: 60px; top: -82px; z-index: 1; height: 20px; width: 20px; } }
11.9995 页面最外层容器设置高度100%占整个页面
处理方式是最外层容器中设置页面高度为100%.
// 页面设置高度100%
uni-page-body,page {
height:100%
}
// 此为最外层高度
.center{
padding-left: 20rpx;
padding-right: 20rpx;
height: 100%;
}
11.9996 button样式修改
实际业务开发中需要修改button样式,比如说需要一个联系客服功能,小程序要求使用button的open-type属性,但是按钮和页面整体显示不符,就需要进行手动修改
比如说如何去边框,如果修改按钮左右间距以及字体大小,设置方式如下:
.concat{
padding-left: 10rpx;
padding-right: 10px;
height: 40px;
margin-left: 20rpx;
border: none;
padding-top: 13rpx;
margin-right: 120px;
font-size: 15px;
}
修改之后如下:
样式修改可以根据实际的样式手动修改大小已达到想要的效果:
10.92 条件强转化为布尔类型!!
!! 为强制转化条件结果(null 空字符串 undefined)为布尔类型
https://www.cnblogs.com/chenguiya/p/15307881.html
使用场景:修改页面之后跳转到指定tabbar页面,不用每次启动之后重新选择页面.设置方式如下:
scroll-view总高度150px,每个view高度50px,总共显示三个数值,支持下滑.
<template>
<view>
<scroll-view scroll-y="true" style="height:150px;">
<view style="height: 50px;">1</view>
<view style="height: 50px;">2</view>
<view style="height: 50px;">3</view>
<view style="height: 50px;">4</view>
<view style="height: 0px;">5</view>
</scroll-view>
</view>
</template>
处理方式是使用
console.log(JSON.stringify(res.data));
// 或是:console.log("打印内容:",res.data);
代替
console.log(res.data);
补充:对于getCurrentPages()
这种函数来说不能使用JSON.stringify
进行打印,原因是获取结果为非json格式对象,进行json处理的时候会解析错误,正确的打印方式是直接打印,参考如下:
let currentPage=getCurrentPages();
console.log("getCurrentPages()",currentPage)
this.newsList=this.newsList.concat(res.data);
// es6实现方式
this.newsList=[...this.newsList,...res.data];
#ifdef:if defined 仅在某平台存在;
#ifndef:if not defined 除了某平台均存在;
#endif:表示结束
官方参考链接: https://uniapp.dcloud.net.cn/tutorial/platform.html#跨端兼容
uniapp中运行操作为开发环境,发行操作为生产环境.判断开发还是生产环境可以使用process.env.NODE_ENV
进行判断.官方参考链接:
https://uniapp.dcloud.net.cn/worktile/running-env.html#判断平台
关于后端接口返回对象集合与前端遍历渲染集合对象属性不一致的情况需要从后端获取数据之后进行组装成方便前端渲染的格式.比如说,获取首页轮播图后端返回集合如下:
[{
"id": 15,
"space_id": 1,
"title": "老兵故事 01",
"type": "image",
"data": {
"image": "http://ts.lagou.uieee.com/api/v2/files/1609",
"link": "https://baijiahao.baidu.com/s?id=1727989741134662012&wfr=spider&for=pc",
"duration": 3
},
"sort": 0,
"created_at": "2022-07-29T03:33:49.000000Z",
"updated_at": "2022-11-12T12:35:06.000000Z"
}]
前端遍历时轮播只需要图片地址image、图片链接link.
swiper组件遍历内容如下:
<swiper-item v-for="(advert,index) in advertList" :key="index">
<view class="swiper-item">
<image :src="advert.image" mode="heightFix" @click="gotoWebview(advert.link)"></image>
</view>
</swiper-item>
script中:
data() {
return {
// 首页轮播图集合
advertList:[]
}
需要将后端接口返回信息按照遍历所需要的内容进行组装,methods中组装方法如下:
// 获取轮播图信息 async getAdvertList(){ await getAdvert({ data: { space:'1,2,3' } }).then(res=>{ this.advertList=res.map(item=> ({ image:item.data.image, // 广告图片地址 link:item.data.link // 广告图片地址 }) ) }).catch((data)=>{ console.log("首页轮播加载失败!"+data) uni.showToast({ title:"网络不给力,请稍后再试!" }) }) }
如果将后端接口中的某个字段组成新的集合,可以参考如下实现:
注意:如果在item循环时候进行打印对象信息,可以按照下面添加:
res.map(item=>
({
image:item.data.image, // 广告图片地址
link:item.data.link // 广告图片地址
},
console.log("打印输出内容:"+item)
)
)
补充一下对象组装方式,后端提供详情查询接口,返回字段信息需要进行封装处理,可以参考如下方式:
await getFeedsDetail( { id:feedId } ).then(res => { this.feedDetail={ feed_content: res.feed_content, feed_img: res.images ? '../../static/logo.png' : this.$baseImgUrl + res.images[0].file, created_at: res.created_at, feed_view_count: res.feed_view_count, hot: res.hot }}).catch((data) => { console.log("动态详情加载失败:" + data) uni.showToast({ title: "网络不给力,请稍后再试!" }) }) }
data中只需要声明对象名即可,不需要声明对象属性,页面直接调用对象属性即可:
data() {
return {
// 动态详情
feedDetail:{}
};
}
onLoad() {
console.log("判断大小:"+ null ? "123":"456"),
console.log("判断大小:"+ (null ? "123":"456"))
}
打印结果:
123
compare.vue:16 判断大小:456
“判断大小:”+ null会解析为表达式,返回true.
vue中null、undefined、‘ ’默认为false。注意
对null与undefined用!操作符时都会产生true的结果。
var o={flag:true}; var test=!!o.flag;//等效于var test=o.flag||false; alert(test);
由于对null与undefined用!操作符时都会产生true的结果。
所以用两个感叹号的作用就在于,
如果明确设置了o中flag的值(非 null/undefined/0""/等值),自然test就会取跟o.flag一样的值;
如果没有设置,test就会默认为false,而不是 null或undefined。
处理方式有多种,这里考虑方便,可以使用uView中的$u.timeFormat
,具体使用可以参考:
https://www.uviewui.com/js/time.html
如果遇到显示时间为1970年01月01日问题,可以将后端返回的时间乘以1000即可.相关代码如下:
<text>{{$u.timeFrom(feedDetail.created_at, 'yyyy年mm月dd日')}}发布</text>
处理后端返回时间格式问题:
created_at: res.created_at * 1000, // 处理uview时间格式化api:timeFrom显示时间为1970年01月01日问题
script中声明变量,函数中可直接使用
<script> // 声明页面变量,用于函数之间值传递 var jsCode = ''; wx.login({ success (res) { console.log("微信授权登录信息:"+JSON.stringify(res)) if (res.code) { // console.log("code返回:"+JSON.stringify(res.code)); jsCode=res.code; console.log("this.jsCode"+jsCode); } else { console.log('登录失败!' + res.errMsg); } } }); </script>
data中声明内容不可再success函数中使用this.变量调用;
success中拿不到vue中的this,可以用bind()绑定,或者用that存储this.
第二种处理方案:
deleteImg(index){
// this.imgList不能直接拿到值的处理方式
var _this = this;
uni.showModal({
title:"确定删除?",
success: function (res) {
console.log('this.imgList',this.imgList)
if (res.confirm) {
_this.imgList.splice(index, 1)
}
}
})
}
补充另一种处理方式:参考:
https://blog.csdn.net/weixin_43401380/article/details/129652552?spm=1001.2014.3001.5501
- tabbar 切换第一次加载时可能渲染不及时,可以在每个tabbar页面的onLoad生命周期里先弹出一个等待雪花(hello
uni-app使用了此方式)- tabbar 的页面展现过一次后就保留在内存中,再次切换 tabbar
页面,只会触发每个页面的onShow,不会再触发onLoad。
setTimeout(()=>{
let currentPage=getCurrentPages();
let page = currentPage.pop();
if (!page) return;
// 可自定义onload加载时初始化参数,如果无需求可不用组装参数
var onloadEvent={
imgClassHeight:this.imgClassHeight,
imgWidth:this.imgWidth,
imgHeight:this.imgHeight,
dynamicId:this.dynamicId
}
// 可自定义onload加载时初始化参数,如果无需求可不用传参
page.onLoad(onloadEvent);
},800) // 指定业务处理完成后多长时间进行强制刷新
this.$nextTick监听数据是否渲染完成,使用场景:用户信息头像修改后需要回显上传到服务器的图片,从上传开始需要显示上传中,上传成功取消显示加载中.
await updateUserInfo({ "userId": this.fromdata.userId, // 当前登录用户id "userName": this.fromdata.userName, // 当前登录用户昵称 "userImg": this.fromdata.userImg, // 当前登录用户头像 "gender":this.fromdata.sex, // 性别 "birthday": this.fromdata.birthday, // 生日 "info":this.fromdata.intro // 个人简介 },{ 'custom': { 'auth': true } } ).then(response => { // 监听dom数据渲染完成取消加载 this.$nextTick(() => { uni.hideLoading() }) }).catch((data) => { uni.showToast({ title: data.data.msg, icon : 'none' }) })
common下创建api.js并定义全局公共方法
/** * 页面跳转 * @author txm * * @param {String} url 需要跳转的index页面的路径 */ const goToIndex = (url) => { uni.switchTab({ url, success: function (res) { console.log(res) }, fail: function (e) { console.log(e) } }) } /** * 消息弹窗 * @author txm * * @param {String} title 标题 * @param {Number} duration 窗口动画持续时间,单位为 ms * @param {String} icon */ const showMsg=(title,icon='none',duration=1500)=>{ uni.showToast({ title, duration, icon }); } //注册定义的方法 export const api={ goToIndex, showMsg }
main.js中导入api.js
// 全局自定义方法
import {api} from './common/api.js'
Vue.prototype.$api=api;
页面中使用:
this.$api.showMsg('用户身份已过期,请重新登陆!') //消息弹窗
this.$api.goToIndex('/pages/index/index') //跳转首页
很多场景中需要通过request返回的值做业务判断,uview中request不清楚如何获取返回值,可以通过data中定义变量的形式获取返回值,then方法中对需要用到的返回值进行页面全局赋值,在方法调用的地方之后就可以直接使用返回值,提供一种变通方案.
// 查询用户限制信息
await this.serverFindUserLimitInfo()
// restPickCount 在serverFindUserLimitInfo方法中的then中进行赋值,此处可以直接调用
if(this.restPickCount == 0){
this.showAdModal()
return
}
success中await this.serverFindAdIsExceedSetting()
无法识别await,处理方式:在success后面添加async.
async beforeSendMsg(param = {}) { await this.checkIsAllowSendMsg() if(this.restChatCount <= 0){ this.chatText='' return uni.showModal({ content: '当日已耗尽,完成任务?', success: async function (res) { if (res.confirm) { await this.serverFindAdIsExceedSetting() if(this.exceedAdCountFlag){ this.$api.showMsg('当日任务已完成!') return } this.showAd() } else if (res.cancel) { console.log('用户点击取消'); } }.bind(this) }); } async serverFindAdIsExceedSetting() { await findAdIsExceedSetting({ 'custom': { 'auth': true } }).then(response => { this.exceedAdCountFlag=response.data }).catch((data) => { this.$api.showMsg(data.data.msg) }) },