当前位置: 首页 > news >正文

uni-app学习--基础组件使用、页面生命周期、本地存储、网络请求、条件编译、路由跳转

文章目录

  • 1. 基本组件的使用
    • 1. text文本组件的使用
    • 2. view视图容器组件的使用
    • 3. button按钮组件的使用
    • 4. image组件的使用
    • 5. map组件
  • 2. uni-app中的样式
    • 1. uni-app:px2rpx计算
  • 3. uni-app的数据绑定
    • 1. 基本的数据绑定
    • 2. v-bind,v-for,v-on
  • 4. uni-app的生命周期
    • 1. uni-app 应用的生命周期
    • 2. 页面的生命周期
    • 3. onPullDownRefresh: 监听下拉刷新
    • 4. onReachBottom: 上拉加载
  • 5. 网络请求
    • 1. 发送请求: uni-app 原生api
    • 2. 项目封装http.js 发送请求
      • 文件路径:lib/http/index.js
      • lib/http.js
      • lib/request.js
  • 6. 数据缓存
    • 1. 异步uni.setStorage,同步setStorageSync
    • 2. 异步uni.getStorage,同步getStorageSync
    • 3. 异步uni.removeStorage,同步removeStorageSync
  • 7. 图片的上传和预览
    • 1. uni.chooseImage(object): 图片上传
    • 2. uni.previewImage(object): 图片预览
    • 3. camera组件
  • 8. 条件编译跨端兼容
  • 9. uni中导航的跳转和传参
    • 1. 使用navigator组件进行跳转
    • 2. 使用编程式导航进行跳转
    • 3. 项目封装的 $navigate 进行跳转
  • 10. 组件的创建和生命周期
  • 11. 组件通讯
  • 12、小程序运行含未引入组件报错

1. 基本组件的使用

uni-app提供了丰富的基础组件给开发者,开发者可以像搭建积木一样,组合各种组件拼接成自己的应用 uni-app中的组件,就像html中的div,p,span等标签的作用一样,用于搭建页面的基础结构 https://uniapp.dcloud.net.cn/component

1. text文本组件的使用

属性类型默认值必填说明
selectabelbooleanfalse文本是否可选
spacestring显示连续空格,可选参数: ensp,emsp,nbsp ensp:中文字符空格一半大小 emsp:中文字符空格大小 nbsp:根据字体设置的空格大小
decodebooleanfalse是否解码,支持:5+APP,H5,微信小程序

•text组件相当于行内标签,在同一行显示(相当于span标签)
•除了文本节点以外的其他节点都无法长按选中
组件内只支持嵌套 ,不支持其它组件或自定义组件,否则会引发在不同平台的渲染差异。但text嵌套text在小程序中布局是有问题的。所以不推荐text嵌套组件

 <text>text组件</text><!-- text 组件使用 --><text><text>嵌套</text></text><view><!-- 长按可选中文本 --><text selectable>详情页呀详情页</text></view><view><!-- 显示连续空格 --><view><!-- ensp 两个个空格=一个字符大小 --><text space="ensp">详情页呀  详情页</text></view><view><!-- emsp 一个空格=一个字符大小 --><text space="emsp">详情页呀 详情页</text></view><view><!-- nbsp 三个空格=一个字符大小 --><text space="nbsp">详情页呀   详情页</text></view></view><view><!-- 解码 --><text decode>&amp;</text><text decode selectable>&lambda;</text></view>

2. view视图容器组件的使用

类似于HTML的div
组件属性:

属性类型默认值必填说明
hover-classstringnone指定按下去的样式类,当hover-class=“none”,没有点击效果
hover-stop-propagationblooeanfalse指定是否阻止本阶段的祖先阶段出现点击态
hover-start-timenumber50按住后多久出现点击态,单位毫秒
hover-stay-timenumber400手指松开后点击态保留事件,单位毫秒
<!-- view 组件使用 -->
<view class="f-content" hover-class="f-active"><view class="content" hover-class="content-active" :hover-stop-propagation="true" :hover-stay-time="1000">呀哈哈</view>
</view>

3. button按钮组件的使用

组件属性:

属性类型默认值说明
sizestringdefault按钮的大小,可选:default,mini
typeStringdefault按钮的样式类型,可选:primary,default,warn
plainBooleanfalse按钮式否镂空,背景色透明
disabledBooleanfalse按钮是否可点击
loadingBooleanfalse按钮名称是否显示loading图标状态

type: - primary: 微信小程序、360小程序为绿色,App、H5、百度小程序、支付宝小程序、飞书小程序、快应用为蓝色,字节跳动小程序为红色,QQ小程序为浅蓝色。如想在多端统一颜色,请改用default,然后自行写样式 - default: 白色 - warn: 红色

<view><text>button组件</text><button>呀哈哈</button><button size="mini" type="warn">呀哈哈</button><button type="primary">呀哈哈</button><button type="primary" plain>呀哈哈</button><button type="primary" disabled>呀哈哈</button><button type="primary" plain loading>呀哈哈</button>
</view>

4. image组件的使用

组件属性:

属性类型默认值说明平台差异说明
srcstring图片资源地址仅支持相对路径、绝对路径,支持 base64 码;
modeStringscaleToFill图片裁剪、缩放的模式
lazy-loadBooleanfalse图片懒加载。只针对page与scroll-view下的image有效微信小程序、百度小程序、字节跳动小程序、飞书小程序
fade-showBooleantrue图片显示动画效果仅App-nvue 2.3.4+ Android有效
webpBooleanfalse在系统不支持webp的情况下是否单独启用webp。默认false,只支持网络资源。微信小程序2.9.0
show-menu-by-longpressBooleanfalse开启长按图片显示识别小程序码菜单微信小程序2.7.0
draggableBooleantrue是否能拖动图片H5 3.1.1+、App(iOS15+)
@errorHandleEvent当错误发生时,发布到 AppService 的事件名,事件对象event.detail = {errMsg: ‘something wrong’}
@loadHandleEvent当图片载入完毕时,发布到 AppService 的事件名,事件对象event.detail = {height:‘图片高度px’, width:‘图片宽度px’}

mode常用缩放
1、缩放: aspectFit: 保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。
2、缩放: aspectFill: 保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。
3、缩放:scaleToFill: 不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素
4、缩放: widthFix: 宽度不变,高度自动变化,保持原图宽高比不变
5、缩放: heightFix: 高度不变,宽度自动变化,保持原图宽高比不变 App 和 H5 平台 HBuilderX 2.9.3+ 支持、微信小程序需要基础库 2.10.3
6、裁剪: top: 不缩放图片,只显示图片的顶部区域
7、裁剪: bottom: 不缩放图片,只显示图片的底部区域
8、裁剪: center: 不缩放图片,只显示图片的中间区域 - 裁剪: left 不缩放图片,只显示图片的左边区域 - 裁剪: right 不缩放图片,只显示图片的右边区域
9、裁剪: top left: 不缩放图片,只显示图片的左上边区域 - 裁剪: top right 不缩放图片,只显示图片的右上边区域 - 裁剪: bottom left 不缩放图片,只显示图片的左下边区域
10、裁剪: bottom right: 不缩放图片,只显示图片的右下边区域

<view><text>image组件</text><!-- 缩放:aspectFit 保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。 --><!-- 缩放: aspectFill 保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。 --><image src="http://destiny001.gitee.io/image/cxk.gif"></image><image src="http://destiny001.gitee.io/image/cxk.gif" mode="aspectFit"></image><image src="http://destiny001.gitee.io/image/cxk.gif" mode="aspectFill"></image>
</view>

5. map组件

参考【uni-app】申请高德地图key,封装map.js,实现H5、iOS、Android通过getlocation获取地图定位信息

2. uni-app中的样式

  • rpx 即响应式px, 一种根据平面宽度自适应的动态单位。以750宽的平面为基准,750rpx恰好为屏幕宽度。屏幕变宽,rpx实际显示效果会等比放大

  • 使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束

  • 支持基本常用的选择器class,id,element第

  • 在uni-app中不支持使用*选择器

  • page相当于body节点

  • 定义在APP.vue中的样式为全局样式,作用于每一个页面。在page目录下的vue文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖APP.vue中相同的选择器

  • uni-app支持使用字体图标,使用方式与普通web项目相同,需要注意:

  • 字体文件小于40kb,uni-app会自动将其转化为base64格式

  • 字体文件大于等于40kb, 需开发者自己转换,否则不生效

  • 字体文件的引用路径推荐使用~@开通的绝对路径

@font-face {
font-family: test-icon;
src:url('~@/static/iconfont.ttf');
}
  • 如何使用scss或者less
<view class="box">呀哈哈<text class="iconfont icon-tupian icon"></text> 
</view>
<style lang="scss">
@import url('./style.css');
.box{width: 375rpx;height: 375rpx;background-color: gray;font-size: 16rpx;color: #fff;.icon{color: red;}
}
</style>
<!-- App.vue 全局样式 -->
<style>/*每个页面公共css */@import url('./static/fonts/iconfont.css');
</style>

1. uni-app:px2rpx计算

rpx和px的区分和转换:
开发者可以通过设计稿基准宽度计算页面元素 rpx 值,设计稿 1px 与框架样式 1rpx 转换公式如下:
设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx
换言之,页面元素宽度在 uni-app 中的宽度计算公式: 750 * 元素在设计稿中的宽度 / 设计稿基准宽度
举例说明:
若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设为:750 * 100 / 750,结果为:100rpx

若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 里面的宽度应该设为:750 * 100 / 640,结果为:117rpx。

若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在 uni-app 里面的宽度应该设为:750 * 200 / 375,结果为:400rpx。
注意:

  • rpx 是和宽度相关的单位,屏幕越宽,该值实际像素越大。如不想根据屏幕宽度缩放,则应该使用 px 单位。
  • 如果开发者在字体或高度中也使用了 rpx ,那么需注意这样的写法意味着随着屏幕变宽,字体会变大、高度会变大。
  • 如果你需要固定高度,则应该使用px - rpx不支持动态横竖屏切换计算,使用rpx建议锁定屏幕方向 - 设计师可以用 iPhone6 作为视觉稿的标准

3. uni-app的数据绑定

1. 基本的数据绑定

基本的数据绑定和vue一致

<template><view>{{"数据绑定"}}<view>{{name}}</view><view>{{"hello word"}}</view><view>{{2+3}}</view><view>{{flag?"哦嚯嚯":"咦嘻嘻"}}</view><!-- v-bind --><image v-bind:src="url"></image><!-- <image :src="url"></image> --><!-- v-for --><view v-for="(item, index) in arr" :key="item.id">姓名:{{item.name}} --- 年龄:{{item.age}}</view><!-- v-on --><view @click="handleFClick" style="width: 375rpx;height: 375rpx;background-color: darkcyan;padding: 10rpx;"><button type="primary" size="mini" v-on:click.stop="handleClick($event,20)">按钮</button><!-- <button type="primary" size="mini" @click="handleClick($event, 20)">按钮</button> --></view></view>
</template>
<script>export default {data() {return {flag:false,name:"呀哈哈",}},
</script>

2. v-bind,v-for,v-on

<template><view>{{"数据绑定"}}<view>{{name}}</view><view>{{"hello word"}}</view><view>{{2+3}}</view><view>{{flag?"哦嚯嚯":"咦嘻嘻"}}</view><!-- v-bind --><image v-bind:src="url"></image><!-- <image :src="url"></image> --><!-- v-for --><view v-for="(item, index) in arr" :key="item.id">姓名:{{item.name}} --- 年龄:{{item.age}}</view><!-- v-on --><view @click="handleFClick" style="width: 375rpx;height: 375rpx;background-color: darkcyan;padding: 10rpx;"><button type="primary" size="mini" v-on:click.stop="handleClick($event,20)">按钮</button><!-- <button type="primary" size="mini" @click="handleClick($event, 20)">按钮</button> --></view></view>
</template><script>export default {data() {return {flag:false,name:"呀哈哈",url:"http://destiny001.gitee.io/image/cxk.gif",arr:[{id:1,age:10,name:"呀哈哈"},{id:2,age:12,name:"哟嚯嚯"},{id:3,age:18,name:"哦呵呵"}]}},methods: {handleClick(e, num){console.log("子-按钮点击",e, num);},handleFClick(){console.log("父-冒泡点击");}}}
</script><style lang="scss">
</style>

4. uni-app的生命周期

1. uni-app 应用的生命周期

生命周期:一个对象从创建、运行、销毁的整个过程被称为生命周期 生命周期函数:在生命周期宏每个阶段都会伴随着每一个函数的触发,这些函数被称为生命周期函数
uni-app支持如下应用生命周期函数

函数名说明
onLaunch当uni-app初始化完成时触发(全局只触发一次)
onShow当uni-app启动,或从后台进入前台显示
onHide当uni-app从前台进入后台
onError当uni-app报错时触发

应用的生命周期写在App.vue中

<script>export default {onLaunch: function() {console.log('App Launch')},onShow: function() {console.log('App Show')},onHide: function() {console.log('App Hide')},onError: function(err) {console.log(err);}}
</script>

2. 页面的生命周期

页面的生命周期

函数名说明
onLoad监听页面加载,其参数为上个页面传递的数据,参数类型为object(用于页面传参),触发一次
onShow监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回当前页面, 可触发多次
onReady监听页面初次渲染完成
onHide监听页面隐藏, 可触发多次
onUnLoad监听页面卸载
onPullDownRefresh监听用户下拉动作,一般用于下拉刷新
onReachBottom页面滚动到底部的事件(不是 scroll-view滚到底),常用于下拉下一页数据
onTabItemTap点击 tab 时触发,参数为Object, 微信小程序、QQ小程序、支付宝小程序、百度小程序、H5、App、快手小程序、京东小程序

执行顺序:onLoad 页面加载 => onShow 页面显示 => onReady 页面渲染完成

onTabItemTap返回的json对象说明:

  • index: Number, 被点击tabItem的序号,从0开始
  • pagePath: String, 被点击tabItem的页面路径
  • text: String, 被点击tabItem的按钮文字

3. onPullDownRefresh: 监听下拉刷新

  1. onPullDownRefresh: 监听用户下拉动作,一般用于下拉刷新
    在 js 中定义 onPullDownRefresh 处理函数(和onLoad等生命周期函数同级),监听该页面用户下拉刷新事件。
    页面开启下拉刷新方法:
  2. 需要在 pages.json 里,找到的当前页面的pages节点,并在 style 选项中开启 enablePullDownRefresh。 当处理完数据刷新后, uni.stopPullDownRefresh:关闭下拉刷新 ,可以停止当前页面的下拉刷新。
    pages.json:
{"path" : "pages/message/message","style": {"navigationBarTitleText": "呀哈哈","enablePullDownRefresh": true  }
},
  1. uni.startPullDownRefresh(Object): 开启下拉刷新 ,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。

4. onReachBottom: 上拉加载

onReachBottom: 页面滚动到底部的事件(不是 scroll-view滚到底),常用于下拉下一页数据

<template><view @touchstart="start" @touchend="end" @touchmove="move">uni-app 生命周期<button @click="handlePullDown">下拉刷新</button><view v-for="(item,index) in list" :key="index"><text>name: {{item}} --- index: {{index}}</text></view><u-button v-if="showTab">展示切换tab</u-button></view>
</template>
<script>export default {data() {return {showTab:true,startData: {clientX: '',clientY: '',},list:new Array(10).fill('').map((item,index)=>item='msg_'+index),}},onPullDownRefresh() {console.log("触发下拉刷新了。");setTimeout(()=>{let addArr = Array(10).fill("").map((item,index)=>item = "msg_"+(index+this.list.length));this.list = [...this.list,...addArr];uni.stopPullDownRefresh();console.log("下拉刷新结束。");},1000)},onReachBottom() { // 页面上拉触底事件触发时距页面底部距离默认 50pxconsole.log("页面滚动到底部了");let addArr = Array(10).fill("").map((item,index)=>item = "msg_"+(index+this.list.length));this.list = [...this.list,...addArr];},onLoad(options){console.log("onLoad -- 生命周期页面加载了。");},onShow(){console.log("onShow -- 生命周期页面显示了。");},onReady(){console.log("onReady -- 生命周期页面初次渲染完成了。");},onHide(){console.log("onHide -- 生命周期页面隐藏了。");},methods: {// 下拉刷新handlePullDown(){uni.startPullDownRefresh();},// 触摸touch事件start(e){  //@touchstart 触摸开始this.startData.pageX = e.changedTouches[0].pageX;   //手指按下时的X坐标         this.startData.pageY = e.changedTouches[0].pageY;   //手指按下时的Y坐标console.log('this.startData', this.startData)},end(){// this.showTab = true;},move(event) {  //@touchmove触摸移动let touch = event.touches[0];  //滑动过程中,手指滑动的坐标信息 返回的是Objcet对象console.log(touch.pageY)if(touch.pageY < this.startData.pageY) {console.log('向下移动')this.showTab = false;}else{console.log('向上移动')this.showTab = true;}},}}
</script>

5. 网络请求

在uni中可以调 uni.request方法进行网络请求 在小程序网络相关的api在使用前需要配置域名白名单(本地环境不需要,发布上线时再修改) uni.request(Object)部分参数:uni.request

属性类型默认值必填说明
urlString开发者服务器接口地址
dataObject/String/ArrayBuffer请求的参数
headerObject设置请求的header,header中不能设置Referer
methodStringGET有效值:GET, POST,PUT, DELETE, CONNECT, HEAD, POTIONS, TRACE
timeoutNumber60000超时事件,单位ms
dataTyoeStringjson如果设为json, 会阐释对返回的数据做一次JSON.parse
responseTypeStringtext设置响应的数据类型,合法值:text、arraybuffer
successFunction收到开发者服务器成功返回的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

1. 发送请求: uni-app 原生api

<button @click="handleGetData">GET请求</button>
<script>
methods:{handleGetData(){uni.request({url:"http://localhost:8082/api/getlunbo",success(res) {console.log(res);},fail() {},complete() {}})}
}
</script>

注:小程序如发生失败可在:详情=>本地设置=>勾选不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书

2. 项目封装http.js 发送请求

文件路径:lib/http/index.js

import request from './http.js'
// import file from './file.js'  //todo 跟http合并为一个
import Config from '.env'// 接口默认超时时间毫秒
const Timeout = Config.service.timeout.default
const TimeoutObject = {errorNo: '408',errorInfo: '请求超时,请检查网络连接'
}
const NotFoundObject = {errorNo: '404',errorInfo: '无效的请求地址'
}
const http = {/*** Form表单请求接口* @param {String} url     请求地址* @param {Object} option  请求参数* @param {Number} timeout 请求超时时间,单位:毫秒*/formRequest: (url, option, timeout) => {return Promise.race([new Promise((resolve, reject) => {if (!url) {return reject(NotFoundObject)}let config = {valString: false,timeout: timeout}request.post(url, option, config).then(r => resolve(r)).catch(e => reject(e))}),new Promise((resolve, reject) => {setTimeout(() => reject(TimeoutObject), timeout)})])},/*** JSON请求接口* @param {String} url     请求地址* @param {Object} option  请求参数* @param {Number} timeout 请求超时时间,单位:毫秒*/jsonRequest: (url, option, timeout = Timeout) => {return Promise.race([new Promise((resolve, reject) => {if (!url) {return reject(NotFoundObject)}let config = {timeout: timeout,valString: option.valString == undefined ? false : option.valString,isConvert: option.isConvert == undefined ? true : option.isConvert,header: { // JSON格式'Content-Type': 'application/json'},transformRequest: [data => { // JSON序列化// 去除空数组,防止IAR报错data = JSON.stringify(data, (_key, val) => (val instanceof Array && val.length === 0) ?undefined : val)return data}]}// 发送异步请求request.post(url, option, config).then(r => resolve(r)).catch(e => reject(e))}),new Promise((resolve, reject) => {setTimeout(() => reject(TimeoutObject), timeout)})])},/*** JSON请求接口* @param {String} url     请求地址* @param {Object} option  请求参数* @param {Number} timeout 请求超时时间,单位:毫秒*/jsonGetRequest: (url, option, timeout = Timeout) => {return Promise.race([new Promise((resolve, reject) => {if (!url) {return reject(NotFoundObject)}let config = {timeout: timeout,valString: option.valString == undefined ? false : option.valString,isConvert: option.isConvert == undefined ? true : option.isConvert,header: { // JSON格式'Content-Type': 'application/json'},transformRequest: [data => { // JSON序列化// 去除空数组,防止IAR报错data = JSON.stringify(data, (_key, val) => (val instanceof Array && val.length === 0) ?undefined : val)return data}]}// 发送异步请求request.get(url, option, config).then(r => resolve(r)).catch(e => reject(e))}).catch(e=>console.log(e)),new Promise((resolve, reject) => {setTimeout(() => reject(TimeoutObject), timeout)})])},/*** 文件上传接口* @param {String} url     请求地址* @param {Object} option  请求参数* @param {Number} timeout 请求超时时间,单位:毫秒*/fileRequest: (url, option, timeout = Timeout) => {return Promise.race([new Promise((resolve, reject) => {if (!url) {return reject(NotFoundObject)}let config = {timeout: timeout,header: {'Access-Type': 'register'}}// 用独立的实例发送异步请求request.post(url, option, config).then(r => resolve(r)).catch(e => reject(e))}),new Promise((resolve, reject) => {setTimeout(() => reject(TimeoutObject), timeout)})])}
}
export default http;

lib/http.js

import Request from './request.js'
import Config from '.env'
// import LS from '../storage'
// import { isJsonString } from '../utils'
// import { showAlert } from '../alert'
// 是否开启字段转换
const isEnableConvert = Config.service.isConvert// 创建http实例
const httpFetch = new Request();// request拦截器
httpFetch.interceptor.request(async config => {// // 获取用户会话// let r = await LS.getAccessToken()// if (r && r.ok && r.data.token) {// 	config.data['curr_session_id'] = r.data.token// }// // 设置客户端IP地址// r = await LS.getClientIp()// if (r && r.ok && r.data.clientIp) {// 	config.data['curr_ip'] = r.data.clientIp// }// // 设置市场编码  todo// if (Config.market) {// 	config.data['market_id'] = Config.market// }// if (isEnableConvert && config.data) {// 	let item = {},// 		valString = config.valString == undefined ? true : config.valString,// 		isConvert = config.isConvert == undefined ? true : config.isConvert// 	delete config.isConvert// 	delete config.valString// 	convert(config.data, item, isConvert, valString)// 	config.data = item// }return config
})
// response拦截器
httpFetch.interceptor.response(rsp => {if (!rsp.data) return rsp// ie中rsp.data返回为string类型,chorme为obj类型if (typeof rsp.data === 'string' && isJsonString(rsp.data)) {rsp.data = JSON.parse(rsp.data)}// 兼容IAR模式追加data模式if (rsp.data.data) {rsp.data = rsp.data.data.length === 1 ? rsp.data.data[0] : rsp.data.data}// 获取错误码let errInfo = ''const errCode = getErrorCode(rsp)/*** 9008错误码处理* 对不起,您缺少访问权限*/if (errCode === '9008' || errCode === 9008) {errInfo = '对不起,您缺少访问权限'doLogout(errInfo, () => {})return new Promise((resolve, reject) => {})}/*** 9004错误码处理* 此账号在异地登录*/if (errCode === '9004' || errCode === 9004) {errInfo = getErrorInfo(rsp)doLogout(errInfo)return new Promise((resolve, reject) => {})}/*** 9007错误码处理* 会话已失效,请重新登录*/if (errCode === '9007' || errCode === 9007) {errInfo = '会话已失效,请重新登录'doLogout(errInfo)return new Promise((resolve, reject) => {})}// 删除多余的字段cleanInvalidAttr(rsp)// 获取最终的返回结果let result = rsp.data// 参数名称格式转换if (canConvert(rsp, result)) {let tempItem = {}if (Array.isArray(result)) {tempItem = result.map(obj => {let innerItem = {}// convert(obj, innerItem, false, false)return innerItem})} else {// convert(result, tempItem, false, false)}result = tempItem}// 如果有错误统一按照错误处理if (errCode !== '' && errCode !== '0' && errCode!==undefined && errCode!==null) {return Promise.reject(result)}return result
})/*** 退出登录处理* @param {*} errInfo * @param {*} callback */
function doLogout(errInfo, callback) {// const func = callback ? callback : () => {// 	// 清空本地缓存// 	LS.clearNativeData()// 	// 跳转到登录页面同时清除历史记录防止后退// 	uni.reLaunch({// 		url: 'user/login',// 	});// }// return showAlert({// 	title: '提示',// 	message: errInfo// }, func)
}
// 获取错误编号
function getErrorCode(rsp) {const r = rsp.datareturn r.error_code || r.errorCode || r.error_no || r.errorNo
}
// 获取错误信息
function getErrorInfo(rsp) {const r = rsp.datareturn r.error_info || r.errorInfo
}
// 清理多余的字段
function cleanInvalidAttr(rsp) {// 删除多余的字段const r = rsp.dataif (r.data !== undefined && r.data == null) {delete rsp.data.data}if (r.dataInfo !== undefined && r.dataInfo == null) {delete rsp.data.datainfo}if (r.data_info !== undefined && r.data_info == null) {delete rsp.data.data_info}if (r.error_extinfo !== undefined && r.error_extinfo == null) {delete rsp.data.error_extinfo}
}
// 是否需要参数名称格式转换
function canConvert(rsp, result) {// let b = hasConvert(rsp.config.url)return isEnableConvert && (null != result && typeof result === 'object') && rsp.config.url
}
/*** 网络异常处理* @param {*} err */
function networkError(err) {const {code,message} = errreturn {errorCode: code,errorInfo: message,success: false}
}
/*** 公有方法:判断是否是json格式* @param {*} str */
function isJsonString(str) {if (typeof str === 'string') {try {var obj = JSON.parse(str)if (typeof obj === 'object' && obj) {return true}return false} catch (e) {return false}}
}
function showAlert(option, handler) {uni.showModal({title: '提示',content: option.message,showCancel: false,success: handler});
}export default httpFetch;

lib/request.js

import Config from '.env'export default class Request {config = {baseUrl: Config.service.baseUrl,header: {'Content-Type': 'application/json;charset=UTF-8'},method: 'GET',dataType: 'json',responseType: 'text',timeout: Config.service.timeout.default || 60000,success() {},fail() {},complete() {}}static posUrl(url) {/* 判断url是否为绝对路径 */return /(http|https):\/\/([\w.]+\/?)\S*/.test(url)}interceptor = {request(f) {if (f) {Request.requestBeforeFun = f}},response(f) {if (f) {Request.requestComFun = f}}}static requestBeforeFun(config) {return config}static requestComFun(response) {return response}// 更改基础请求路径setConfig(f) {this.config = f(this.config)}request(options = {}) {options.baseUrl = options.baseUrl || this.config.baseUrloptions.dataType = options.dataType || this.config.dataTypeoptions.url = Request.posUrl(options.url) ? options.url : (options.baseUrl + options.url)options.data = options.data || {}options.header = options.header || this.config.headeroptions.method = options.method || this.config.methodreturn new Promise(async (resolve, reject) => {let next = truelet _config = nulloptions.complete = (response) => {let statusCode = response.statusCoderesponse.config = _configresponse = Request.requestComFun(response)if (statusCode === 200) { // 成功resolve(response)} else {if (response){reject(response)}else{reject(null);}}}let cancel = (t = 'handle cancel') => {let err = {errMsg: t,config: afC}reject(err)next = false}let afC = {...this.config,...options}_config = {...afC,...await Request.requestBeforeFun(afC, cancel)}if (!next) returnuni.request(_config)}).catch(e=>console.log(e));}// 设置 get 和 post 请求 需要url请求地址 data所需参数 get(url, data, options = {}) {options.url = urloptions.data = dataoptions.method = 'GET'// 使用 this.request 发起请求,传入参数,获取数据return this.request(options)}post(url, data, options = {}) {options.url = urloptions.data = dataoptions.method = 'POST'return this.request(options)}
}

6. 数据缓存

1. 异步uni.setStorage,同步setStorageSync

uni.setStorage(object):将数据存储在本地缓存中指定的key中,会覆盖掉原来key对应的内容,是一个异步接口。
参数:

属性类型必填说明
keystring本地缓存中的指定的 key
dataAnydefault按钮的样式类型,可选:primary,default,warn
plainBoolean需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

同步存储 :uni.setStorageSync

2. 异步uni.getStorage,同步getStorageSync

uni.getStorage(Object): 异步从本地缓存中异步获取指定 key 对应的内容。 参数:

属性类型必填说明
keystring本地缓存中的指定的 key
successFunction接口调用的回调函数,res = {data: key对应的内容}
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

同步获取 :uni.getStorageSync

3. 异步uni.removeStorage,同步removeStorageSync

uni.removeStorage(Object): 异步从本地缓存中异步移除指定 key。

属性类型必填说明
keystring本地缓存中的指定的 key
successFunction接口调用的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

同步删除 :uni.removeStorageSync
清理本地数据缓存:uni.clearStorage(),uni.clearStorageSync()

<script>export default {data() {return {item:{msg:"信息描述"}}},onLoad() {console.log("onLoad -- 生命周期页面加载了。");},onUnload() {console.log("导航页面卸载。");},methods:{goDetail(){uni.navigateTo({url:"/pages/detail-component/detail?id='1'&name='yhh'"})},goMessage(){uni.setStorageSync('name', 'yhh');uni.switchTab({url:"/pages/message/message"})},redirectDetail(){uni.redirectTo({url:"/pages/detail-component/detail?id='1'"})},urlDetail(){uni.navigateTo({url:"/pages/detail-component/detail?item="+encodeURIComponent(JSON.stringify(this.item))})}}}
</script> 

7. 图片的上传和预览

1. uni.chooseImage(object): 图片上传

1、uni.chooseImage(object) 方法从本地相册选择图片或使用相机拍照
2、App端如需要更丰富的相机拍照API(如直接调用前置摄像头),可使用组件https://uniapp.dcloud.net.cn/component/camera.html ,
uniApp开发调用摄像头拍照, 想要设置默认为前置摄像头: 使用uni.chooseImage 是无法设置这一默认值的,只有chooseVideo(即拍摄视频)支持

  • 如果对兼容性没有要求,只是在小程序用,可使用组件 camera,通过参数 device-position控制, 但不支持H5,App端

2. uni.previewImage(object): 图片预览

uni.previewImage(object):图片预览

3. camera组件

页面内嵌的区域相机组件。注意这不是点击后全屏打开的相机。https://uniapp.dcloud.net.cn/component/camera.html
支持:微信小程序,百度小程序,QQ小程序,快应用,快手小程序,京东小程序 ,在 App 和 H5 端,可以使用API方式来调用全屏摄像头,而不是组件内嵌方式,详见:uni.chooseImage 和 uni.chooseVideo
相关api: https://uniapp.dcloud.net.cn/api/media/camera-context.html#:
创建并返回 camera 组件的上下文 cameraContext 对象。

<template><view>图片上传<u-button @click="chooseImg">上传图片</u-button><image v-for="item in imgArr" :src="item" :key="item" @click="viewImg"></image><br /><text>camera组件,仅支持小程序</text><u-button @click="getCamera">拍照</u-button><!-- 相机拍照 --><view class="" v-if="ifPhoto"><!-- 相机 --><camera :device-position="convert" flash="off" @error="error" class="camera">    </camera><!-- 操作 --><view class="padding bottom_code flex align-center justify-between"><!-- 返回 --><view class="code_button" @click="back"><image src="../../static/tabs/icon_return.png" mode="aspectFill"></image></view><!-- 拍照 --><view class="code_button" @click="takePhoto"><image src="../../static/tabs/camera.png" mode="aspectFill"></image></view><!-- 切换摄像头 --><view class="code_button" @click="showConvert"><image src="../../static/tabs/camera_switch.png" mode="aspectFill"></image></view></view></view><!-- 照片查看 --><view class="" v-if="src"><view><image :src="src" mode="aspectFit"></image></view><!-- 操作 --><view style="display: flex;justify-content: space-around;"><button size="mini" type="default" @click="anew">重新拍摄</button><button size="mini" type="primary" @click="uploading">上传</button></view></view></view>
</template><script>export default {data() {return {imgArr:[],//true 拍照 false 查看ifPhoto: false,//照片src: null,oldSrc: null,//前置或后置摄像头,值为front, backconvert: 'front'}},methods: {chooseImg(){uni.chooseImage({count:5, // 默认9sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有// sourceType: ['camera'], // 拍照success: (res) => {console.log(res,"===>图片");this.imgArr = res.tempFilePaths;}})},viewImg(){// 预览图片uni.previewImage({urls: this.imgArr,loop:true,indicator:'number',longPressActions: {itemList: ['发送给朋友', '保存图片', '收藏'],success: function(data) {console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');},fail: function(err) {console.log(err.errMsg);},}});},getCamera(){this.ifPhoto = true;},//拍照takePhoto() {const ctx = uni.createCameraContext();ctx.takePhoto({quality: 'high',success: (res) => {console.log(res);this.src = res.tempImagePathif (this.src != null) {this.ifPhoto = false}}});},//摄像头启动失败error(e) {console.log(e.detail);},//切换摄像头showConvert() {if (this.convert == 'front') {// 后置this.convert = 'back'} else {// 前置this.convert = 'front'}},//返回back() {// uni.navigateBack({//   delta: 1// })this.ifPhoto = false;this.src = this.oldSrc;},//重新anew() {this.oldSrc = this.src;this.src = '';this.ifPhoto = true;},//上传uploading() {console.log('上传成功');}}}
</script><style lang="scss">
// 相机
.camera {width: 100%;height: 50vh;
}
//操作
.bottom_code {position: fixed;bottom: 10rpx;left: 0;width: 100%;height: 120rpx;// background-color: #1CA6EC;display: flex;justify-content: space-around;.code_button {width: 90rpx;height: 90rpx;// border-radius: 50%;image {width: 100%;height: 100%;}}
}
.img_code {width: 100%;height: 80vh;padding-top: 180rpx;image {width: 100%;height: 100%;}
}
</style>

8. 条件编译跨端兼容

https://uniapp.dcloud.net.cn/tutorial/platform.html
uni-app已将常用的组件、js api封装到框架中,开发者按照uni-app规范开发即可保证多平台兼容,大部分业务均可直接满足 但每个平台都有自己的一些特性,因此会存在一些无法跨平台的情况。 * 大量写if else , 会造成代码执行性能低下和管理混乱 * 编译到不同的工程后二次修改,会让后续升级变得很麻烦
在 C 语言中,通过 #ifdef、#ifndef 的方式,为 windows、mac 等不同 os 编译不同的代码。 uni-app 参考这个思路,为 uni-app 提供了条件编译手段,在一个工程里优雅的完成了平台个性化实现。
以 #ifdef 或 #ifndef 加 %PLATFORM% 开头,以 #endif 结尾

  • ifdef:if defined 仅在某平台存在
  • ifndef:if not defined 除了某平台均存在
  • %PLATFORM%:平台名称
// 仅出现在 App 平台下的代码
#ifdef APP-PLUS
需条件编译的代码
#endif// 除了 H5 平台,其它平台均存在的代码
#ifndef H5
需条件编译的代码
#endif// 在 H5 平台或微信小程序平台存在的代码(这里只有||,不可能出现&&,因为没有交集)
#ifdef H5 || MP-WEIXIN
需条件编译的代码
#endif
条件编译是利用注释实现的,在不同语法里注释写法不一样,js使用 // 注释、css 使用 /* 注释 */、vue/nvue 模板里使用 <!-- 注释 -->;``````html
<template><!-- #ifdef H5 --><view>这段文字仅在h5页面展示</view><!-- #endif --><!-- #ifdef MP-WEIXIN --><view>这段文字仅在微信小程序页面展示</view><!-- #endif --></view>
</template>
<script>export default {data() {return {}},methods: {onLoad() {// #ifdef H5console.log("仅在h5页面打印出来\(^o^)/~");// #endif// #ifdef MP-WEIXINconsole.log("仅在微信小程序页面打印出来\(^o^)/~");// #endif},}
</script>
<style>
/* #ifdef H5 */
view{background-color: aquamarine;
}
/* #endif */
/* #ifdef MP-WEIXIN */
view{background-color: coral;
}
/* #endif */
</style>

%PLATFORM% 可取值如下:

  • APP-PLUS : App
  • APP-PLUS-NVUE或APP-NVUE : App nvue 页面
  • APP-ANDROID : App Android 平台 仅限 uts文件
  • APP-IOS : App iOS 平台 仅限 uts文件
  • H5 : H5
  • MP-WEIXIN : 微信小程序
  • MP-ALIPAY : 支付宝小程序
  • MP-BAIDU : 百度小程序
  • MP-TOUTIAO : 字节跳动小程序
  • MP-LARK : 飞书小程序
  • MP-QQ : QQ小程序
  • MP-KUAISHOU : 快手小程序
  • MP-JD : 京东小程序
  • MP-360 : 360小程序
  • MP : 微信小程序/支付宝小程序/百度小程序/字节跳动小程序/飞书小程序/QQ小程序/360小程序
  • QUICKAPP-WEBVIEW : 快应用通用(包含联盟、华为)
  • QUICKAPP-WEBVIEW-UNION : 快应用联盟
  • QUICKAPP-WEBVIEW-HUAWEI : 快应用华为
    static 目录的条件编译
    在不同平台,引用的静态资源可能也存在差异,通过 static 的条件编译可以解决此问题,static 目录下新建不同平台的专有目录,专有目录下的静态资源只有在特定平台才会编译进去。

9. uni中导航的跳转和传参

1. 使用navigator组件进行跳转

https://uniapp.dcloud.net.cn/component/navigator.html
1、该组件类似HTML中的组件,但只能跳转本地页面。目标页面必须在pages.json中注册。
2、url有长度限制,太长的字符串会传递失败,可使用窗体通信、全局变量,或encodeURIComponent等多种方式解决
3、tabbar不可通过url进行传参,可以通过在main.js定义全局变量,或使用本地存储

2. 使用编程式导航进行跳转

https://uniapp.dcloud.net.cn/api/router.html#navigateto
•uni.navigateTo(OBJECT):保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面。
•uni.redirectTo(OBJECT):关闭当前页面,跳转到应用内的某个页面。
•uni.switchTab(OBJECT):跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
•uni.navigateBack(OBJECT):关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。
•uni.preloadPage(OBJECT):预加载页面,是一种性能优化技术。被预载的页面,在打开时速度更快。支持:H5,App-nvue
注:由于生命周期onLoad只执行一次,当点击返回按钮返回上一级页面时,并不会触发上一页页面的onLoad以到达传递参数的目的。因为navigateTo是保留当前页面,跳转到下一级页面。所以如果需要再返回上一级页面传递参数时,可以使用:页面通讯uni.on(),localStorage等。

<template><view><view>navigator导航跳转</view><!-- 1. 跳转到普通页面 --><navigator url="/pages/detail-component/detail?id='1'&name='yhh'"><button size="mini" type="default">跳转至详情页1</button></navigator><!-- 2. 跳转到tabbar页面:open-type="switchTab",tabbar不可通过url进行传参,可以通过在main.js定义全局变量,或使用本地存储 --><navigator url="/pages/message/message?id='1'" open-type="switchTab"><button size="mini" type="default">跳转至信息页</button></navigator><!-- 3. 在当前页面打开,并关闭当前页面:open-type="redirect" --><navigator url="/pages/detail-component/detail?id='1'" open-type="redirect"><button size="mini" type="default">跳转至详情页2</button></navigator><!-- 4. url长度限制:encodeURIComponent(str) 编码 --><navigator :url="'/pages/detail-component/detail?item='+encodeURIComponent(JSON.stringify(item))"><button size="mini" type="default">跳转至详情页3</button></navigator><br /><view>编程式导航跳转</view><button size="mini" type="default" @click="goDetail">跳转至详情页1</button><button size="mini" type="default" @click="goMessage">跳转至信息页</button><button size="mini" type="default" @click="redirectDetail">跳转至详情页2</button><button size="mini" type="default" @click="urlDetail">跳转至详情页3</button></view>
</template><script>export default {data() {return {item:{msg:"信息描述"}}},onLoad() {console.log("onLoad -- 生命周期页面加载了。");},onUnload() {console.log("导航页面卸载。");},methods:{goDetail(){uni.navigateTo({url:"/pages/detail-component/detail?id='1'&name='yhh'"})},goMessage(){uni.setStorageSync('name', 'yhh');uni.switchTab({url:"/pages/message/message"})},redirectDetail(){uni.redirectTo({url:"/pages/detail-component/detail?id='1'"})},urlDetail(){uni.navigateTo({url:"/pages/detail-component/detail?item="+encodeURIComponent(JSON.stringify(this.item))})}}}
</script>
<style>

3. 项目封装的 $navigate 进行跳转

main.js 封装:

// 扩展路由导航
Vue.prototype.$navigate = (route, params = {}, option = {}) => {try {if (route.includes('?')) {let p = route.split('?')[1]route = route.split('?')[0]p.split("&").map(it => {params[it.split('=')[0]] = it.split('=')[1]})}let paramsData = ""let history = (option.history === false || option.history === 'false') && option.history.toString()let switchTab = params.switchTab && params.switchTab.toString() || 'false';let navigateFun = history === 'false' ? uni.redirectTo : switchTab == 'true' ? uni.reLaunch : uni.navigateTo;route = route.startsWith('/') ? route : '/' + routeroute = route.startsWith('/pages') ? route : '/pages' + routeObject.keys(params).forEach(function(key) {paramsData += key + '=' + encodeURIComponent(params[key]) + '&'})paramsData = paramsData == "" ? "" : '?' + paramsData.substring(0, paramsData.length - 1)return navigateFun({url: route + paramsData,});} catch (e) {console.log(e)}
}
// 使用:confirmPick(item){this.jumpByDefault('/receipt/pick/pickDetail', { detailId: item.id, otpType:'insert', title:'新增仓单提货' });},
jumpByDefault (link, opt = {}) {this.$navigate(link, opt, {})},// url有长度限制,太长的字符串会传递失败,使用 encodeURIComponent进行传参:
handleBook(item){this.$navigate('/pages/ctl/custody/custodyDetail', { detail: encodeURIComponent(JSON.stringify(item)) });
},// 接受参数:
onLoad(params){console.log( JSON.parse(decodeURIComponent(params.detail)) ) 
},

10. 组件的创建和生命周期

组件的生命周期
• beforeCreated: 在实例初始化之后被调用
• created: 在实例创建完成后被立即调用
• beforeMount: 在挂载开始前被调用
• mounted: 挂载到实例之后被调用。此处并不能确定子组件被全部挂载,如需要子组件完成挂载之后再执行操作可以使用$nextTick
• beforeUpdate: 数据更新时调用,发生在虚拟DOM达不到之前,仅支持H5
• updated: 由于数据更新导致的虚拟DOM重新渲染和达不到,在这一行调用,仅支持H5
• beforeDestory: 实例销毁之前调用,在这异步实例仍然可以使用
• destoryed:
实例销毁后调用,调用后,vue实例指示的所有东西都会解绑,所有事件监听器都会被移除,所有的子实例也会被销毁。

因为生命周期属于组件,所以当虚拟DOM树对比完后,只会对此组件的虚拟DOM树要更新的部分做更新。 而子组件在虚拟DOM树中,只知道子组件的构造器(Ctor),传入的数据(data)和子项(children)有没有变化,不关心子组件内部的虚拟DOM树。 因此, 只能保证这个组件要去渲染它的子组件,却无法保证它的子组件内部是如何渲染的。
当使用nextTick时,将在微任务(不支持微任务的浏览器将回退至宏任务)堆栈中入栈你写的回调。如果所有子组件都已经下载完毕,并在Vue中定义,
则从根组件往后渲染时,因为用的都是同步方法,微任务将在这些同步方法后被执行,所以大多数时候可以通过nextTick获取子组件渲染后的DOM节点。

但是如果实例化组件的时候,有其他微任务入栈,就要看微任务队列的执行顺序了,所以无法完全保证。

对于异步组件,由于网络原因,import微任务总在$nextTick之后,所以总是拿不到子组件的DOM。 而在setTimeout一定时间之后,由于setTimeout是宏任务,所以一般会在渲染后执行。 但对于异步组件,如果由于网络延迟,导致微任务在宏任务之后入栈,则在setTimeout的回调中仍无法获取子组件的DOM。
简单的来说, 由于有异步执行顺序的影响,只能保证单独组件内部的执行顺序,无法保证其他组件的解析注册执行顺序。

11. 组件通讯

• 父子组件之间通讯:props
• 同层级组件之间通讯:https://uniapp.dcloud.net.cn/api/window/communication.html

12、小程序运行含未引入组件报错

微信开发者工具从 1.05.2201210 版本开始,对小程序项目新增了无依赖文件过滤能力。
如果某个 js 文件被静态分析显示是无依赖文件,在实际运行时又被其他 js 文件 require 引用了,则会在工具模拟器中报错这个错误。
解决方式: 关闭过滤无依赖文件:project.config.json 中 settings 选项添加 ignoreDevUnusedFiles: false , ignoreUploadUnusedFiles: false,清除缓存,然后再重新编译就好了

相关文章:

uni-app学习--基础组件使用、页面生命周期、本地存储、网络请求、条件编译、路由跳转

文章目录 1. 基本组件的使用1. text文本组件的使用2. view视图容器组件的使用3. button按钮组件的使用4. image组件的使用5. map组件 2. uni-app中的样式1. uni-app&#xff1a;px2rpx计算 3. uni-app的数据绑定1. 基本的数据绑定2. v-bind,v-for,v-on 4. uni-app的生命周期1. …...

Cweek4+5

C语言学习 十.指针详解 6.有关函数指针的代码 代码1&#xff1a;(*(void (*)())0)(); void(*)()是函数指针类型&#xff0c;0是一个函数的地址 (void(*)())是强制转换 总的是调用0地址处的函数&#xff0c;传入参数为空 代码2&#xff1a;void (*signal(int, void(*)(int))…...

Segment Anything CSharp| 在 C# 中通过 OpenVINO™ 部署 SAM 模型实现万物分割

​ OpenVINO™ C# API 是一个 OpenVINO™ 的 .Net wrapper&#xff0c;应用最新的 OpenVINO™ 库开发&#xff0c;通过 OpenVINO™ C API 实现 .Net 对 OpenVINO™ Runtime 调用.Segment Anything Model&#xff08;SAM&#xff09;是一个基于Transformer的深度学习模型&#x…...

企业应如何选择安全合规的内外网文件摆渡系统?

网络隔离是一种安全措施&#xff0c;旨在将网络划分为不同的部分&#xff0c;以减少安全风险并保护敏感信息。常见的隔离方式像物理隔离、逻辑隔离、防火墙隔离、虚拟隔离、DMZ区隔离等&#xff0c;将网络隔离成内网和外网。内外网文件摆渡通常指在内部网络&#xff08;内网&am…...

一分钟有60秒,这个有趣的原因你知道吗?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

二叉树最大宽度

文章目录 前言二叉树最大宽度1.题目解析2.算法原理3.代码编写 总结 前言 二叉树最大宽度 1.题目解析 给你一棵二叉树的根节点 root &#xff0c;返回树的 最大宽度 。 树的 最大宽度 是所有层中最大的 宽度 。 每一层的 宽度 被定义为该层最左和最右的非空节点&#xff08;即…...

React@16.x(24)自定义HOOK

目录 1&#xff0c;介绍2&#xff0c;简单举例2.1&#xff0c;获取数据1.2&#xff0c;计时器 2&#xff0c;自定义 HOOK 相比类组件 1&#xff0c;介绍 将一些常用的&#xff0c;跨组件的函数抽离&#xff0c;做成公共函数也就是 HOOK。自定义HOOK需要按照HOOK的规则来实现&a…...

群体优化算法----树蛙优化算法介绍以及应用于资源分配示例

介绍 树蛙优化算法&#xff08;Tree Frog Optimization Algorithm, TFO&#xff09;是一种基于群体智能的优化算法&#xff0c;模拟了树蛙在自然环境中的跳跃和觅食行为。该算法通过模拟树蛙在树枝间的跳跃来寻找最优解&#xff0c;属于近年来发展起来的自然启发式算法的一种 …...

常见汇编指令

下面是一些包含汇编指令 MOV、PUSH、POP、LEA、LDS、ADD、ADC、INC、SUB、SBB、DEC、CMP、MUL、DIV、AND、OR、XOR、NOT、TEST、SHL、SAL、SHR、SAR、ROL、ROR、RCL、RCR、LODS、MOVS 的例题。这些例题展示了每条指令的用法及其作用。 1. MOV 指令 MOV AX, BX ; 将寄存器 B…...

Mysql学习(七)——约束

文章目录 四、约束4.1 概述4.2 约束演示4.3 外键约束 总结 四、约束 4.1 概述 概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。目的&#xff1a;保证数据库中数据的正确、有效性和完整性。分类&#xff1a; 4.2 约束演示 根据需求&…...

Redis实战篇02

1.分布式锁Redisson 简单介绍&#xff1a; 使用setnx可能会出现的极端问题&#xff1a; Redisson的简介&#xff1a; 简单的使用&#xff1a; 业务代码的改造&#xff1a; private void handleVoucherOrder(VoucherOrder voucherOrder) {Long userId voucherOrder.getUserI…...

怎么用PHP语言实现远程控制两路照明开关

怎么用PHP语言实现远程控制两路开关呢&#xff1f; 本文描述了使用PHP语言调用HTTP接口&#xff0c;实现控制两路开关&#xff0c;两路开关可控制两路照明、排风扇等电器。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称厂商1智能WiFi墙…...

Docker面试整理-什么是多阶段构建?它的好处是什么?

多阶段构建是 Docker 在 Dockerfile 中引入的一个功能,允许你在单个 Dockerfile 中使用多个构建阶段,但最终只生成一个轻量级的镜像。这是通过在一个 Dockerfile 中定义多个 FROM 指令来实现的,每个 FROM 指令都可以使用不同的基础镜像,并开始一个新的构建阶段。 多阶段构建…...

ENSP校园网设计实验

前言 哈喽&#xff0c;我是ICT大龙。本次更新了使用ENSP仿真软件设计校园网实验。时间比较着急&#xff0c;可能会有错误&#xff0c;欢迎大家指出。 获取本次工程文件方式在文章结束部分。 拓扑设计 拓扑介绍---A校区 如图&#xff0c;XYZ大学校园网设计分为3部分&#xff0…...

【Spring框架全系列】SpringBoot_3种配置文件_yml语法_多环境开发配置_配置文件分类(详细)

文章目录 1.三种配置文件2. yaml语法2.1 yaml语法规则2.2 yaml数组数据2.3 yaml数据读取 3. 多环境开发配置3.1 多环境启动配置3.2 多环境启动命令格式3.3 多环境开发控制 4. 配置文件分类 1.三种配置文件 问题导入 框架常见的配置文件有哪几种形式&#xff1f; 比如&#xf…...

华为坤灵路由器初始化的几个坑,含NAT配置

1、aaa密码复杂度修改&#xff1a; #使能设备对密码进行四选三复杂度检查功能。 <HUAWEI>system-view [HUAWEI]aaa [HUAWEI-aaa]local-aaa-user password policy administrator [HUAWEI-aaa-lupp-admin]password complexity three-of-kinds 2、本地用户名长度必须大…...

【RAG入门教程04】Langchian的文档切分

在 Langchain 中&#xff0c;文档转换器是一种在将文档提供给其他 Langchain 组件之前对其进行处理的工具。通过清理、处理和转换文档&#xff0c;这些工具可确保 LLM 和其他 Langchain 组件以优化其性能的格式接收数据。 上一章我们了解了文档加载器&#xff0c;加载完文档之…...

请求 响应

在web的前后端分离开发过程中&#xff0c;前端发送请求给后端&#xff0c;后端接收请求&#xff0c;响应数据给前端 请求 前端发送数据进行请求 简单参数 原始方式 在原始的web程序中&#xff0c;获取请求参数&#xff0c;需要通过HttpServletRequest 对象手动获取。 代码…...

技术周总结2024.06.03~06.09(K8S HikariCP数据库连接池)

文章目录 一、06.05 周三1.1) 问题01: 容器领域&#xff0c;Docker与 K8S的区别和联系Docker主要功能和特点&#xff1a;使用场景&#xff1a; Kubernetes (K8S)主要功能和特点&#xff1a;使用场景&#xff1a; 联系和区别联系&#xff1a;区别&#xff1a; 结合使用总结 二、…...

【JavaScript】了解 Sass:现代 CSS 的强大预处理器

我已经从你的 全世界路过 像一颗流星 划过命运 的天空 很多话忍住了 不能说出口 珍藏在 我的心中 只留下一些回忆 &#x1f3b5; 牛奶咖啡《从你的全世界路过》 在前端开发领域&#xff0c;CSS 是必不可少的样式表语言。然而&#xff0c;随着项目复杂度的…...

下载安装Thonny并烧录MicroPython固件至ESP32

Thonny介绍 一、Thonny的基本特点 面向初学者&#xff1a;Thonny的设计初衷是为了帮助Python初学者更轻松、更快速地入门编程。它提供了直观易懂的用户界面和丰富的功能&#xff0c;降低了编程的门槛。轻量级&#xff1a;作为一款轻量级的IDE&#xff0c;Thonny不会占用过多的…...

YOLOv5改进 | 主干网络 | 将主干网络替换为轻量化的ShuffleNetv2【原理 + 完整代码】

&#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 目标检测是计算机视觉中一个重要的下游任务。对于边缘盒子的计算平台来说&#xff0c;一个大型模型很难实现实时检测的要求。基于一系列消融…...

LeetCode:字母异位词分组

文章收录于LeetCode专栏 LeetCode地址 字母异位词分组 题目 给定一个字符串数组&#xff0c;将字母异位词组合在一起。字母异位词指字母相同&#xff0c;但排列不同的字符串。所有输入均为小写字母&#xff0c;且不考虑答案输出的顺序。   示例1&#xff1a; 输入: strs [“…...

技术与业务的完美融合:大数据BI如何真正提升业务价值

数据分析有一点经典案例 沃尔玛的啤酒和尿布案例 开始做BI的时候&#xff0c;大家肯定都看过书&#xff0c;那么一定也看过一个经典的案例&#xff0c;就是沃尔玛的啤酒和尿布的案例。这个案例确实很经典&#xff0c;但其实是一个失败的案例。为什么这么说呢&#xff1f;很明显…...

计网复习资料

一、选择题&#xff08;每题2分&#xff0c;共40分&#xff09; 1. Internet 网络本质上属于&#xff08; &#xff09;网络。 A.电路交换 B.报文交换 C.分组交换 D.虚电路 2.在 OSI 参考模型中,自下而上第一个提供端到端服务的是( )。 A.数据链路层 B.传输…...

华为策略流控

以下脚本仅做参考&#xff0c;具体IP地址和接口请按照现场实际情况写入。 [Huawei]acl 3001 [Huawei-acl-adv-3001]rule permit ip source 192.168.1.10 0.0.0.0 destination 192.168.2.10 0.0.0.0 //匹配需要做测试的源和目标地址 [Huawei-acl-adv-3001]rule permit ip sour…...

刷代码随想录有感(98):动态规划——爬楼梯

题干&#xff1a; 代码&#xff1a; class Solution { public:int climbStairs(int n) {if(n 1)return 1;if(n 2)return 2;vector<int>dp(n 1);dp[0] 0;dp[1] 1;dp[2] 2;for(int i 3; i < n; i){dp[i] dp[i - 1] dp[i - 2];}return dp[n];} }; 其实就是斐波…...

零基础入门篇①⑦ Python可变序列类型--集合

Python从入门到精通系列专栏面向零基础以及需要进阶的读者倾心打造,9.9元订阅即可享受付费专栏权益,一个专栏带你吃透Python,专栏分为零基础入门篇、模块篇、网络爬虫篇、Web开发篇、办公自动化篇、数据分析篇…学习不断,持续更新,火热订阅中🔥专栏限时一个月(5.8~6.8)重…...

基于NodeJs 的Vue安装和创建项目

基于NodeJs 的Vue安装和创建项目 一、Node.js的下载与安装 下载地址&#xff1a; https://nodejs.org/en/download/prebuilt-installer 安装完之后&#xff0c;启动 cmd命令行&#xff0c;验证 Node.js 是否安装成功 二、配置npm的全局模块的存放路径以及缓存的路径 注&…...

【简单介绍下DALL-E2,什么是DALL-E2?】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…...

做代购需要什么网站/百度获客

开始于2020年6月15日 方法str.title()以首字母大写的方式显示每个单词 name "ada lovelace" print(name.title()) # Ada Lovelace 方法str.upper()和str.lower() name "Ada Lovelace" print(name.upper()) # ADA LOVELACE print(name.lower()) # ada lov…...

广州科 外贸网站建设/网销是做什么的

最近发现DOMDocument对象很重要,还有XMLHTTP也很重要 注意大小写一定不能弄错. 属性: 1Attributes 存储节点的属性列表(只读) 2childNodes 存储节点的子节点列表(只读) 3dataType 返回此节点的数据类型 4Definition 以DTD或XML模式给出的节点的定义(只读) …...

杭州做网站设计公司/优化器

语音合成&#xff1a;也被称为文本转换技术&#xff08;TTS&#xff09;&#xff0c;它是将计算机自己产生的、或外部输入的文字信息转变为可以听得懂的、流利的口语输出的技术。 刚开始项目需求订单实时播报&#xff0c;最初采用的H5的语音合成Speech Synthesis API&#xff…...

正规的网店平台有哪些/网站如何提升seo排名

torch.manual_seed(seed)设定生成随机数的种子&#xff0c;并返回一个torch._C.Generator对象&#xff0c;参数&#xff1a;seed(int or long):种子。torch.initial_seed()返回生成随机数的原始种子值&#xff08;python long&#xff09;。torch.get_rng_state() 返回随机生成…...

apache wordpress rewrite/官网关键词优化价格

030-云E办_RabbitMQ_简单模式队列一、介绍简单模式队列1、RabbitMQ发送消息使用三个角色&#xff1a;1. producing 消息的生产者。2. queue队列&#xff1a;3. consuming 消费者&#xff1a;2、hello3、如何实现hello4、生产者和消费者&#xff0c;解读代码&#xff1a;1.生产者…...

wordpress评论时选填/影视网站怎么优化关键词排名

微信的JS-SDK通过config接口注入权限验证配置&#xff0c;官网上的文档说的很清楚&#xff1a;wx.config({debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来&#xff0c;若要查看传入的参数&#xff0c;可以在pc端打开&#xff0c;参数信息会通过log打出…...