易遗漏事件总结

关闭/保存后

移动端技巧总结

阿里图库

在原有的基础上加新图标

该代码替换掉原有的 iconfont.css

src 请求头要加https,要不然移动端会不显示阿里图标

onBackPress 返回上一级

onBackPress() {// ...自定义操作---提示(是否确认退出)
if (this.ruleForm.Id) {uni.navigateTo({// 跳转到平常页面url: '/pages/business/B_WayBill/B_WayBill'})} else {// 跳转到 tabbar 页面uni.switchTab({url: '/pages/work/work'})}return true
}

实现这种提示:

<!--关闭按钮显示与否--><u-modal :closeOnClickOverlay="true" @close="show = false" @cancel="show = false" cancelText="继续编辑"confirmText="下次再编辑" :show="show" @confirm="close" :showCancelButton="true" title="还差一点就添加成功了"></u-modal>
// 点击左上角返回按钮触发
onBackPress() {this.show = truereturn true
}close(){uni.navigateTo(...)
}

❗close事件不要用 navigateBack 会进入死循环

✨路径传参

uni.navigateTo({url: `/pages/business/B_WayBill_Add/components/cargoMessage?rowData=${JSON.stringify(this.rowData)}&cargoData=${JSON.stringify(row)}`
});

❗如果传递的参数是对象,需要用 JSON.stringify 转成字符串,后面接受数据再用 JSON.parse 转成 object

条件编辑

  • // #ifdef H5
    // #endif// #ifdef APP-PLUS<!-- #ifndef MP-WEIXIN --> ✨除了这种之外<!-- #ifdef MP-WEIXIN -->
    

页面下拉刷新事件

async onPullDownRefresh() {this.getData()// 停止刷新uni.stopPullDownRefresh()
}// 同时要在 pages 里面设置

返回顶部

<!-- 返回顶部的按钮组件 -->
<u-back-top class="u-back-top" :iconStyle="{color:'#fff'}" icon="arrow-up" :scroll-top="scrollTop"></u-back-top>// 监听返回顶部按钮的距离
onPageScroll(e) {this.scrollTop = e.scrollTop;
}

页面重置到顶部

uni.pageScrollTo({scrollTop: 0,duration: 0
});

搜索定位

uni.pageScrollTo({scrollTop:dom元素(vue里面的ref).offsetTop,
})

图片预览

uni.previewImage({current: "",urls: [e],
})

页面跳转

// 页面会刷新触发onLoad(有表单组件的话需要存起来
uni.navigateTo()
❗url要带'/',eg:'/pages/...'// 页面不会刷新(有表单组件
uni.navigateBack()

uniapp开发

获取this.$refs为空对象或者为undefined

解决方法

非H5端只能用于获取自定义组件,不能用于获取内置组件实例(如:view、text)

ref组件使用了条件渲染,即v-if、v-show,这些DOM节点在mounted无法被访问到

使用了 v-for 循环动态绑定ref(大部分时请求后端数据动态渲染DOM),this.$ref[name]获取的是数组

  • 用法应该为 dom[x].xx

非H5端只能用于获取自定义组件,不能用于获取内置组件实例(如:view、text) $el只支持H5端

const query = uni.createSelectorQuery().in(this)query.select(`#${res.Data.BillInfo.BillNo}`).boundingClientRect(data => {console.log(data) // 返回节点的相对坐标信息top、bottom等 //查询当前屏幕的滚动位置等信息uni.createSelectorQuery().selectViewport().scrollOffset(result => {// result.scrollTopuni.pageScrollTo({scrollTop: Math.abs(data.top) - 300,duration: 100});}).exec();}).exec();

熟悉业务需求

  • 完成状态下没有完成中的操作(状态
  • 完成业务后重置刷新数据
  • 初始赋值

可以使用JavaScript的reduce()方法来合并具有相同属性和值的对象

const mergedTaleData = data.tableData.reduce((acc, curr) => {const existingObj = acc.find(obj => obj.PickBill_Id == curr.PickBill_Id && obj.FeeName == curr.FeeName && obj.Currency == curr.Currency);console.log(existingObj, acc, curr);if (existingObj) {existingObj.AccTotal = xeUtils.add(existingObj.AccTotal, curr.AccTotal);existingObj.Acc = xeUtils.add(existingObj.Acc, curr.Acc);} else {acc.push({ ...curr, AccTotal: curr.AccTotal, Acc: curr.Acc });}return acc;}, []);

响应式数组置空

  • resultData.value.length = 0

有时候 disabled 的样式安卓端与ios端可能不一样

/deep/ .uni-input-input:disabled { // 安卓color: #666;
}/deep/ .is-disabled { // ioscolor: #666;
}

异步操作放在actions中,actions通过commit调用mutations中方法操作state

地址转经纬度

uni.request({url: 'https://restapi.amap.com/v3/geocode/geo?parameters',method: 'GET',data: {key: '', //高德地图keyaddress: '广东省湛江市' // 详细地址},success: (res) => {let lo = res.data.geocodes[0].location.split(',')[0]let la = res.data.geocodes[0].location.split(',')[1]console.log(lo,la);navigaToShop({latitude: lo,longitude: la,stationname: res.data.geocodes[0].formatted_address})},fail: (err) => {this.$toast(err)}
})

APP(IOS Android )转到高德地图、百度地图、腾讯地图

// getMap.jsexport function getCurLocation() {uni.getLocation({geocode: true,type: 'gcj02',success: (res) => {}})}//打开第三方地图export function toMapAPP(latitude, longitude, address) {let url = ''if (plus.os.name == "Android") { //判断是安卓端let url = "";plus.nativeUI.actionSheet({ //选择菜单title: "选择地图应用",cancel: "取消",buttons: [{title: "腾讯地图"}, {title: "百度地图"}, {title: "高德地图"}]}, function(e) {switch (e.index) {//下面是拼接url,不同系统以及不同地图都有不同的拼接字段case 1://注意referer=xxx的xxx替换成你在腾讯地图开发平台申请的keyurl =`qqmap://map/routeplan?type=drive&from=我的位置&fromcoord=CurrentLocation&to=${address}&tocoord=${latitude},${longitude}&referer=`;break;case 2:url ="baidumap://map/direction?origin=我的位置" +"&destination=name:" + address +"|latlng:" + latitude + "," + longitude +"&coord_type=gcj02&mode=driving&src=andr.baidu.openAPIdemo"break;case 3:url =`amapuri://route/plan/?did=&dlat=${latitude}&dlon=${longitude}&dname=${address}&dev=0&t=0`break;default:break;}if (url != "") {url = encodeURI(url);//plus.runtime.openURL(url,function(e){})调起手机APP应用plus.runtime.openURL(url, function(e) {plus.nativeUI.alert("本机未安装指定的地图应用");});}})} else {// iOS上获取本机是否安装了百度高德地图,需要在manifest里配置// 在manifest.json文件app-plus->distribute->apple->urlschemewhitelist节点下添加//(如urlschemewhitelist:["iosamap","baidumap"])  plus.nativeUI.actionSheet({title: "选择地图应用",cancel: "取消",buttons: [{title: "高德地图"}, {title: "百度地图"}, {title: "腾讯地图"}]}, function(e) {switch (e.index) {case 1:url =`iosamap://path?sourceApplication=applicationName&did=&dlat=${latitude}&dlon=${longitude}&dname=${address}&dev=0&t=0`;break;case 2:url = "baidumap://map/direction?origin=我的位置" +"&destination=name:" + address +"|latlng:" + latitude + "," + longitude +"&coord_type=gcj02&mode=driving&src=ios.baidu.openAPIdemo";break;case 3:url =`qqmap://map/routeplan?type=drive&from=我的位置&fromcoord=CurrentLocation&to=${address}&tocoord=${latitude},${longitude}&referer=`;break;default:break;}if (url != "") {url = encodeURI(url);plus.runtime.openURL(url, function(e) {plus.nativeUI.alert("本机未安装指定的地图应用");});}})}}

uniapp某个容器滚动到底部事件

<scroll-view v-if="actionSheetCurrentItem.remote" :scroll-top="scrollTop" scroll-y="true"@scrolltolower="scrolltolower" style="height: 300px" @scroll="scroll"></scroll-view>scrollTop: 0,
old: {scrollTop: 0
}scroll: function(e) {this.old.scrollTop = e.detail.scrollTop
}// 置顶
// 解决view层不同步的问题this.scrollTop = this.old.scrollTopthis.$nextTick(function() {this.scrollTop = 0});

置顶头部部分

position: fixed;
background-color: skyblue;
height: 50px;
line-height: 50px;
top: 44px;
z-index: 999;
width: 100%;
// app平台的代码
// #ifdef APP-PLUS
position: fixed;
top: 0px;
z-index: 9999;

点击电话调起拨打功能

<a :href="'tel:' + item.VehiclenoCarManTel">{{item.VehiclenoCarManTel}}</a>

PDA(iData)

  • 注意开启以及结束的时机
  • 开启新一个要结束掉上一个
  • ✨使用插件如果要用到 this 要合理的使用箭头函数
// 一般在 onLoad 事件里面开启onLoad(options) {this.getData()// 初始化扫描barcodeModel.initScan((ret) => {});// 获取扫描结果globalEvent.addEventListener('iDataBarcodeEvent', (e) => { // this.searchValue = e.barcodeif (e.barcode) this.PDAScanInoneflag(e.barcode)//连续扫描如果间隔时间比较短,会出现toast不提示的情况,数据可以正常接收到,建议查看控制台输出});TTSSpeech.init((status) => {if (status === 0) {this.ttsInitSuccess = true}}, 'com.iflytek.speechcloud')
}// 结束 一般在onUnLoad 或者根据业务在 onBackPress 中
onBackPress() {// 结束扫描globalEvent.removeEventListener("iDataBarcodeEvent");barcodeModel.closeScan((ret) => {});uni.navigateTo({url: '/pages/business/PDA/PDA'})return true
},

语音播报

const TTSSpeech = uni.requireNativePlugin("MT-TTS-Speech");TTSSpeech.speak({text})

关于封装组件的技巧

  • 分析需求

    • 把页面中可以复用的 ✨结构、样式以及功能✨ 单独抽离成一个
  • 具体步骤

    • Vue.component (全局)components: {}(局部) 注册组件
    • 子:props 接收数据 emits触发父的自定义事件 父::传输数据 @自定义事件
    • 组件传入模板 则定义为插槽 slot
    • 数据或者方法之类的如果需要被调用,记得暴露出来
  • 一个强大的公用组件包含的文件可分为:

    • hooks.js

      • 公共的方法、样式等
    • index.vue
      • 组件主要逻辑
    • porps.js
      • 接受传过来的数据
    • linkColumn.vue
      • 子组件.vue

记得使用数组方法

APP上架到iosStore的注意事项

不用苹果电脑的Xcode↓↓↓

ipa上传工具

APP隐私声明示例

欢迎您使用本软件(以下简称“本服务”),本软件是由xx有限公司(以下简称“本公司”)向员工提供的工作软件。为保证您的权益,便于更好地使用本软件及相应的配套服务,请您务必在注册前认真阅读本协议,若您阅读并接受本协议,使用本软件提供的产品和服务,即视为您受本协议的约束,若您不同意本协议,请勿使用本网站任何产品和服务。一、服务内容本软件运用自己的系统通过互联网络为用户提供软件交易、工程师服务等服务。用户使用本服务需要下载本软件客户端软件,同时,用户必须:1、自行配备上网所需设备,包括个人电脑、调制解调器或其他必备上网装置。2、自行负担个人上网所支付的与此服务有关的电话费用、网络费用。3、基于本软件所提供的服务的重要性,用户应同意:1)提供详尽、准确的个人资料。2)不断更新注册资料,符合及时、详尽、准确的要求,如果您提供的注册资料不合法、不真实的,需自行承担由此引起的责任及后果,本公司保留终止您使用本软件各项服务的权利。4、为防止他人冒用您的身份注册、使用本服务,企鹅外汇可能会给您的手机发送短信进行验证,由此产生的短信费用由本公司支付,您不需支付任何费用。二、服务的提供、修改及终止1、您保证在您同意接受本协议并注册成为本软件用户时,您已经年满18周岁,您是具备完全民事权利能力和完全民事行为能力的自然人。2、在接受本公司各项服务的同时,您同意接受本公司提供的各类信息服务,并在此授权本公司可以向您电子邮件、手机等发送商业信息。3、您有权选择不接受本公司提供的各类信息服务,并进入本软件相关页面进行更改。4、本公司可以提前3天通知,单方终止本协议。5、本软件有权在必要时修改服务条款,若您对本协议的修改有异议,您可以停止使用本软件的网络服务,在此情况下,本软件没有义务传送任何未处理的信息或未完成的服务给您或任何无直接关联的第三方。三、用户隐私制度1、本公司将会采取合法、合理的措施保护用户的个人信息,非经法定原因或用户事先许可,本公司不会向任何第三方透露您的密码、姓名、手机号码等非公开信息。以下情况除外:1)用户授权本软件透露这些信息。2)相关的法律法规或监管机构、司法机构要求本软件提供您的个人资料;国家司法机关符合法律规定并经法定程序的检查及其他操作。3)任何第三方盗用、冒用或未经许可擅自披露、使用或对外公开您的个人隐私资料。4)由您要求网站提供特定服务时,需要把您的姓名和地址提供给第三方的。5)您在使用本服务、参加网站活动或访问网站网页时,自动接收并记录的浏览器端或手机客户端数据,包括但不限于IP地址、网站Cookie中的资料及您要求取用的网页记录。6)本软件从商业伙伴处合法获取的个人信息。 7)我们的产品基于DCloud uni-app(5+App/Wap2App)开发,应用运行期间需要收集您的设备唯一识别码(IMEI/androidID/DEVICE_ID/IDFA、SIM 卡 IMSI信息、OAID)以提供统计分析服务,并通过应用启动数据及异常错误日志分析改进性能和用户体验,为用户提供更好的服务。2、在适合的情况下,并在您同意的前提下,我们会利用您的信息来联络您,为您发送信息。3、您应当妥善保管您的设备和密码及身份信息,对于因密码泄露、身份信息泄露、设备丢失所致的损失,由您自行承担。四、用户行为规范除非法律允许或本公司书面许可,您使用本软件过程中不得从事下列行为:1、删除本软件及其副本上关于著作权的信息。2、对本软件进行反向工程、反向汇编、反向编译,或者以其他方式尝试发现本软件的源代码。3、对本公司拥有知识产权的内容进行使用、出租、出借、复制、修改、链接、转载、汇编、发表、出版、建立镜像站点等。4、对本软件或者本软件运行过程中释放到任何终端内存中的数据、软件运行过程中客户端与服务器端的交互数据,以及本软件运行所必需的系统数据,进行复制、修改、增加、删除、挂接运行或创作任何衍生作品,形式包括但不限于使用插件、外挂或非本公司经授权的第三方工具/服务接入本软件和相关系统。5、通过修改或伪造软件运行中的指令、数据,增加、删减、变动软件的功能或运行效果,或者将用于上述用途的软件、方法进行运营或向公众传播,无论这些行为是否为商业目的。6、通过修改或伪造软件运行中的指令、数据,增加、删减、变动软件的功能或运行效果,或者将用于上述用途的软件、方法进行运营或向公众传播,无论这些行为是否为商业目的。7、自行或者授权他人、第三方软件对本软件及其组件、模块、数据进行干扰。8、其他未经本公司明示授权的行为。 五、适用法律和管辖权1、企鹅外汇注册所在地法律、法规应规范本协议以及本协议各方之间引起的争议,除非存在法律指定适用其他管辖法律。2、在合约一方寻求实现本协议下的权利,或寻求宣告本协议下的任何权利或义务的任何民事诉讼或其他诉讼过程中,各合约方应承担其代理律师的费用和支出。3、本协议的解释语言应为中文。4、本公司可能通过多种语言将本协议或任何其他文件、信息和消息提供给合作方。本协议规定,合作方应当承认及确认本公司工作语言为中文。如果任何文件、信息和消息的非中文表述和中文表述之间出现矛盾和不一致的情况下,双方将以中文文件、信息和消息为标准。

Guideline 2.1 - Information Needed

Dear Review team: After receiving your reason for rejection back, we carefully verified the interior of the application and found nothing wrong with what you said. In order to avoid unnecessary misunderstanding, we specially provide the relevant qualification certificate, and provide the following instructions: 1. Is your app limited to users who belong to the same company? This may include users of company partners, employees, and contractors. No, our app can serve employees and customers of different logistics companies. 2. Is your app designed for a limited or specific group of companies? Yes, our app is specifically for international logistics companies. 3. What features (if any) in the application are intended for public use? No. 4. Determine which countries or territories you plan to release your application in?The app plans to roll out China to China. 5. How do users get an account? We also have a back office system where the administrator gives the user account. 6.  Is there paid content in the app? For example, does the user pay to open an account or use certain features in the app? The app doesn't have a paid feature. Users don't have to pay for any features, and all features are free to try. 7. Who pays for premium content and how do users access it? The App has no payment function, and users can access all content by logging into the app after obtaining an account.

Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage

详细介绍申请这些权限的用处

PC端(Vue)技巧总结

element

多试试插槽,实现个性化样式

<template #title><el-tag effect="dark" size="large" style="margin-right: 10px;">主单号</el-tag>
</template>

loading的多种使用方式

  • 默认loading
    • v-loading 绑定布尔值
  • 自定义loading
    • v-loading="loading"
      element-loading-text="拼命加载中"
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(0, 0, 0, 0.8)"
  • 整页加载

分割组件 splitpanes

import { Splitpanes, Pane } from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';<splitpanes style="height: 100%"><pane :size="40" v-if="!rowData"></pane>
</splitpanes>

vuex 的使用

const state = {lang:getLang(),
}const mutations = {SET_LANG(state, lang){state.lang = langsetLang(lang)}
}const actions = {changeLang({commit}, lang){commit('SET_LANG', lang)}
}export default {namespaced: true,state,mutations,actions,
}
import { mapState } from 'vuex'
import store from '@/store/index.js'computed: {...mapState("addOrderCargo", ["sendMessage", "recieveMessage", "productOptions", "inventoryData", "ruleForm"])
}store.getters.inventoryDatastore.commit('addOrderCargo/setproductOptions', res.data)

自定义指令

指令钩子

const myDirective = {// 在绑定元素的 attribute 前// 或事件监听器应用前调用created(el, binding, vnode, prevVnode) {// 下面会介绍各个参数的细节},// 在元素被插入到 DOM 前调用beforeMount(el, binding, vnode, prevVnode) {},// 在绑定元素的父组件// 及他自己的所有子节点都挂载完成后调用mounted(el, binding, vnode, prevVnode) {},// 绑定元素的父组件更新前调用beforeUpdate(el, binding, vnode, prevVnode) {},// 在绑定元素的父组件// 及他自己的所有子节点都更新后调用updated(el, binding, vnode, prevVnode) {},// 绑定元素的父组件卸载前调用beforeUnmount(el, binding, vnode, prevVnode) {},// 绑定元素的父组件卸载后调用unmounted(el, binding, vnode, prevVnode) {}
}

钩子参数

el:指令绑定到的元素。这可以用于直接操作 DOM。binding:一个对象,包含以下属性。value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2。
oldValue:之前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否更改,它都可用。
arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"。
modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }。
instance:使用该指令的组件实例。
dir:指令的定义对象。
vnode:代表绑定元素的底层 VNode。prevNode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。

使用示例

// VTrim.js ----局部
/***全局去掉输入框前后空格指令*/
function getInput(el){let inputEleif(el.tagName !== 'INPUT'){inputEle = el.querySelector('input')}else{inputEle = el}return inputEle
}function dispathEvent(el,type){const evt = document.creatEvent('HTMLEvents')evt.initEvent(type, true, true)el.dispatchEvent(evt)
}const trimDirective = {mounted(el){const inputEle = getInput(el)const handler = function (event) {const newVal = event.target.value.trim()if (event.target.value !== newVal) {event.target.value = newValdispatchEvent(inputEle, 'input')}}// 回车后过滤空格(因为输入框可以回车调接口查询,所以这时候单纯的失去焦点过滤不起作用,要对回车键单独做一下处理)const keydown = function (event) {if (event.keyCode === 13) {const newVal = event.target.value.trim()if (event.target.value !== newVal) {event.target.value = newValdispatchEvent(inputEle, 'input')}}}el.inputEle = inputEleel._blurHandler = handlerel._keyHandler = keydowninputEle.addEventListener('blur', handler)inputEle.addEventListener('keydown', keydown)},unmounted(el) {const {inputEle} = elinputEle.removeEventListener('blur', el._blurHandler)inputEle.removeEventListener('keydown', el._keyHandler)}
}export default trimDirective;// 使用
import Trim from "@/directives/VTrim";
// directives节点声明
directives:{Trim},// tempalte中使用 <el-input v-trim></el-input>   // 全局
const getInput = elm =>elm instanceof HTMLInputElement ? elm : elm.querySelector('input')
app.directive('focus',{mounted(el,{arg}){if(arg) el.focus?.()else getInput(el)?.focus()}
})

后台管理版本更新

import axios from 'axios'export const isNewVersion = () => {// 开发环境不做判断if (process.env.NODE_ENV === 'development') return// 线上环境判断版本号let url = `//${window.location.host}/version.json?t=${new Date().getTime()}`axios.get(url).then(res => {if (res.status === 200) {let vueVersion = res.data.version || '1.0.0'let localVueVersion = localStorage.getItem('vueVersion')localStorage.setItem('vueVersion', vueVersion)if (localVueVersion && localVueVersion != vueVersion) {alert('检测到新版本,请点击确认刷新页面,加载资源需要一些时间,请稍等!')window.location.reload(true)return}}})
}export default {isNewVersion
}

Vue2

Vue2 data or props 用到另外一个数值,记得函数不能用箭头函数,会把this丢失掉

vue2 引入组件

import yhCascader from '@/components/YhCascader'components:{}// 全局 main.js
import yhUpload from '@/components/yh-upload/yh-upload'

watch

"sendMessage.MailingType": {handler(oldVal, newVal) {this.getSendAddress()},deep: true, // 深度监听immediate: true // 第一次改变就执行}

computed

计算后属性必须渲染后,绑定的方法才会生效这里指就是定义后的变量名在上面html中显示

vue2一个对象中的一个值是一个计算属性

怎么搞?—只有计算属性依赖项变化才回触发

vue3

defineComponent

  • vue3中,新增了 defineComponent ,它并没有实现任何的逻辑,只是把接收的 Object 直接返回,它的存在是完全让传入的整个对象获得对应的类型,可以获得自动提示。

计算属性(一个页面可以使用多个computed和多个 watch)

  • data中的一个值如果依赖另一个值记得写成计算属性,不然不会同步

组合式API

// 1
export dedfault{setup(){...// 要 return 数据、函数 出去return {...}}
}// 2 script setup 语法糖   不需要在setup函数里面写代码了,不需要 return,vue3 自动返回
<script setup></script>

引入组件

import yhCascader from '@/components/YhCascaderexport default {components: {yhCascader}
}

总–总结

判断数据类型

const keyType = data => {let type = Object.prototype.toString.call(data);if (type === '[object String]') {type = 'String';} else if (type === '[object Number]') {type = 'Number';} else if (type === '[object Null]') {type = 'Null';} else if (type === '[object Boolean]') {type = 'Boolean';} else if (type === '[object Array]') {type = 'Array';} else if (type === '[object Object]') {type = 'Object';} else {type = '未进行判断的类型:' + type;}return type;
};

对象包裹对象转换为数组

for in   +   push

filter

赋值数据

const data = res.data || []

封装

将一些通用的参数和函数抽离出来,封装成一个通用的 hook

eg:定义列表页面的分页数据

export const pageHook = () => {return {sort: '',order: 'desc',Foots: '',total: 0,}
}

对象

深拷贝

JSON.parse(JSON.Stringfy())

有key字段,但还需要value字段

  • 直接使用 . 加一个名称属性给 Object

不同属性类型共享同一个 object

对象赋值

for (let key in ruleForm) {ruleForm[key] = value[key]}

callBack 合理使用

封装组件需要注意的点

  • 显示与否

  • 传递数据另给一个 js 文件存放

    • import propsData from './props'

    • // props.js
      export default {leftColumns: {type: Array,default: () => []},
      }
      
  • 个性化–合理利用插槽

    • <slot name="rightTop"></slot>
  • 组件间传递数据

    • props emits
  • 数据更新问题

    • $nextTick

    • 定时器

      • setTimeout(()=> {emits('changeAfter')},200)
  • vue3 在 data 中 使用 compute

    • list:computed(()=>{...})
  • 使用三段式

    • let activeData = isAll ? getLeftData() : leftTableRef.value.getSelected():type="isShowLeftList ? 'info' : 'success'" 
  • 巧用 v-model

      • props:{value: {type: Array,default: () => [],}
        }
        
      • this.$emits('input',data)
        
    • 使用组件 用 v-model

    • v-model 的值就能关联 父里面的 data值了

❗v-if 会影响到 ref 的获取

请求接口参数

  • 拼接参数

    • ?a=${b}&
  • formData

async返回值都是 promise对象

解决:

  • 分开

  • 如果是 promise 的话,用 resolve返回

✨善于利用 uniapp 的 API + Promise

  • 代码式书写,解决先后执行问题

async removeBeforeAsync(id) {this.show = truelet returnBool = falseawait new Promise((resolve, reject) => {uni.showModal({title: '删除文件', //提示标题content: '是否删除该文件', //提示内容showCancel: true, //是否显示取消按钮success: async (res) => {if (res.confirm) { //confirm为ture,代表用户点击确定let res2 = await this.http.post('/api/B_WayBill_Files/DelWayBillFile?Id=' + id, {}, true)if (res2.Status) {this.$toast('删除成功!')} else {this.$toast('删除失败!', 'error')}returnBool = res2.Status} else if (res.cancel) { //cancel为ture,代表用户点击取消returnBool = false}resolve()}})})return returnBool},

请求接口的是否加载可以加在config里面

实现左右滑动

.insure {display: flex;height: 520px;.left {width: 40%;// overflow: auto;.header {}}.right {flex: 1;// overflow: auto;}
}
  • elementUI有个滚动条样式

循环一般用来读取数据,而不要改变响应式数据

根据这个思路,可以把methods或者computed计算完的数据放置于数组中,再在响应式内直接读取数组元素

APP(andriod,ios)热更新

代码:https://blog.csdn.net/itopit/article/details/124620871

借鉴:https://blog.csdn.net/m_xiaozhilei/article/details/126485684

打包的wgt版本要与后端记录的一样,线下打包的可以搞成第一点版本的去测试

// APP.vue
onLauch(){//检查更新// #ifdef APP-PLUSplus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {uni.setStorageSync("curversion", widgetInfo.version);let curversion = widgetInfo.version;console.log("当前版本", curversion);hotupdate.getAppByVersion(curversion, true);});// #endif
}// hotupdate.js
import http from './http.js'function update(fileName) {let downURL = fileName;console.log('下载地址', downURL);//后台显示进度条let dtask = plus.downloader.createDownload(downURL, {},function(d, status) {//下载完成install(d, status);// uni.showModal({//   title: "版本更新",//   content: "新版本已经准备好,是否更新应用?",//   success: (res) => {//     if (res.confirm) {//       install(d, status);//     }//   },// });});start(dtask);
};function start(dtask) {try {dtask.start(); //开启下载任务let prg = 0;let showLoading = plus.nativeUI.showWaiting("正在下载");dtask.addEventListener("statechanged", function(task, status) {switch (task.state) {case 1:showLoading.setTitle("正在下载");break;case 2:showLoading.setTitle("已连接到服务器");break;case 3:prg = parseInt((parseFloat(task.downloadedSize) /parseFloat(task.totalSize)) *100);showLoading.setTitle("  正在下载" + prg + "%  ");break;case 4:plus.nativeUI.closeWaiting();break;}});} catch (err) {plus.nativeUI.closeWaiting();uni.showToast({title: "更新失败-03",mask: false,duration: 1500,});}
};function install(d, status) {//下载完成if (status === 200) {plus.runtime.install(d.filename, {force: false}, function() {plus.nativeUI.closeWaiting();plus.runtime.restart();// plus.nativeUI.alert("应用资源更新完成!是否重启应用!", function() {//   plus.runtime.restart();// });}, function(e) {plus.nativeUI.closeWaiting();console.log("安装wgt文件失败[" + e.code + "]:" + e.message);plus.nativeUI.alert("安装wgt文件失败[" + e.code + "]:" + e.message);});} else {uni.showToast({title: "下载失败",mask: false,duration: 1500,});}
};function close(version) {try {console.log('保存要跳过的版本', version)uni.setStorageSync('skip_version', version);} catch (e) {// error}
};function signOut() {// #ifdef APP-PLUSplus.runtime.quit();// #endif
}export default {getAppByVersion(curversion, back) {console.log("came in");let params = {};if (uni.getSystemInfoSync().platform == "ios") {params = {app: "kdapp",type: "ios",appversion: curversion,};} else {params = {app: "kdapp",type: "android",appversion: curversion,};}// console.log(curversion);http.post(`/api/B_App_Ver_Record/GetNewAppVersion?VersionName=${curversion}`).then((res) => {console.log('version res');console.log(res);if (res.status && res.data[0]) {let result = res.data[0];if (back) {try {const value = uni.getStorageSync('skip_version');console.log('是否跳过当前版本', value, result.versionName)if (value && value === result.versionName) {return;}} catch (e) {}}if (result.versionName != curversion) {// console.log('有新版本要更新', result);// console.log('新版本', result.versionName);// console.log('目前版本', curversion);result.back = back;// if (uni.getSystemInfoSync().platform != "ios") {plus.nativeUI.confirm(result.verDescription || "系统提示", function(e) {if (e.index == 1) {console.log('update', result.filePath);update(http.fileAddress + result.filePath);} else if (result.forceUpdate == 1) {signOut();} else if (result.forceUpdate == 0) {close(result.versionName);}}, {"title": "版本更新","buttons": [result.forceUpdate == 1 ? "退出应用" : "暂不更新", "立即更新"]});// } else {//   uni.showModal({//     title: "版本更新",//     content: "请点击按钮复制链接,粘贴到Safari浏览器打开,下载最新版本",//     confirmText: "点击复制",//     showCancel: false,//     success: () => {//       uni.setClipboardData({//         data: http.fileAddress + result.filePath,//         success: () => {//           uni.showToast({//             title: "复制链接成功,请粘贴到Safari浏览器打开"//           })//         }//       })//     }//   });// }} else if (!back) {//plus.nativeUI.alert("当前已是最新版本!");}} else if (!res.status) console.log('error');uni.showToast({title: res.msg,icon: 'none', //如果要纯文本,不要icon,将值设为'none'duration: 3000 //持续时间为 2秒});} else if (!back) {//plus.nativeUI.alert("当前已是最新版本!");}})}
}

高亮与不高亮基本大小要一样才不会变来边去

请求参数如果没有就不添加:

let params = {}if (this.keyword2) {params["billNo"]=this.keyword2}if (this.startTime2 && this.endTime2) {params["beginTime"]=this.startTime2params["endTime"]=this.endTime2}

uniapp select被table遮挡

.uni-table-scroll{overflow-x: unset;}

this.$set解决新增的对象属性没有响应式(computed无效)

this.$set(this.rowData,'coupon',newVal * num || 0)// 优惠金额

图片

uniapp展示本地图片使用image>标签都可以展示图片。但是<img>标签在网页端和真机模拟都不可以展示图片。

路径直接为 /static/… 不需要相对,不需要@符号。直接从/static目录往下写就行了

数组

新增元素

  • arr.splice(1,0,xx)
  • arr.push(xx)
  • arr.unshfit(xx)

在使用 <script setup> 的单文件组件中,导入的组件可以直接在模板中使用,无需注册

掉起拨打电话接口

<a :href="'tel:' + item.VehiclenoCarManTel">{{item.VehiclenoCarManTel}}</a>

devtools–给你的vue3项目的main.js加上这一句

app.config.devtools = true

vue 循环一定要弄key

  • 要不然顺序变化时会出现错误

js 计算精度问题

自己写公共方法:

/**** 加**/add(arg1, arg2) {​    var r1, r2, m, c;​    try {​      r1 = arg1.toString().split(".")[1].length;​    } catch (e) {​      r1 = 0;​    }​    try {​      r2 = arg2.toString().split(".")[1].length;​    } catch (e) {​      r2 = 0;​    }​    c = Math.abs(r1 - r2);​    m = Math.pow(10, Math.max(r1, r2));​    if (c > 0) {​      var cm = Math.pow(10, c);​      if (r1 > r2) {​        arg1 = Number(arg1.toString().replace(".", ""));​        arg2 = Number(arg2.toString().replace(".", "")) * cm;​      } else {​        arg1 = Number(arg1.toString().replace(".", "")) * cm;​        arg2 = Number(arg2.toString().replace(".", ""));​      }​    } else {​      arg1 = Number(arg1.toString().replace(".", ""));​      arg2 = Number(arg2.toString().replace(".", ""));​    }​    return (arg1 + arg2) / m;},/**** 减**/sub(arg1, arg2) {​    var r1, r2, m, n;​    try {​      r1 = arg1.toString().split(".")[1].length;​    } catch (e) {​      r1 = 0;​    }​    try {​      r2 = arg2.toString().split(".")[1].length;​    } catch (e) {​      r2 = 0;​    }​    m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度​    n = r1 >= r2 ? r1 : r2;​    return Number(((arg1 * m - arg2 * m) / m).toFixed(n));},/**** 乘**/mul(arg1, arg2) {​    var m = 0,​      s1 = arg1.toString(),​      s2 = arg2.toString();​    try {​      m += s1.split(".")[1].length;​    } catch (e) {}​    try {​      m += s2.split(".")[1].length;​    } catch (e) {}​    return (Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) / Math.pow(10, m);},/**** 除**/div(arg1, arg2) {​    var t1 = 0,​      t2 = 0,​      r1,​      r2;​    try {​      t1 = arg1.toString().split(".")[1].length;​    } catch (e) {}​    try {​      t2 = arg2.toString().split(".")[1].length;​    } catch (e) {}​    r1 = Number(arg1.toString().replace(".", ""));​    r2 = Number(arg2.toString().replace(".", ""));​    return (r1 / r2) * Math.pow(10, t2 - t1);},

或者xe-utils 解决 js 加减乘除精度问题

善于使用对象处理(存储)多数据

let obj = {}
obj[key] = xx

❗一定一定要记得复杂数据类型的特殊性,需求如果是不改变原数据一定要深拷贝

// 一般使用 JSON.stringify 进行拷贝---在获取的时候用JSON.parse来解构就行了在用store存储、作为参数传递过去、赋值等等操作一定要注意

❗❗❗removeEventListener

addEventListener 之后一定要记得 removeEventListener
  • 取消对一个全局事件的监听。

插件的结束时期

数据传输 传过去=》再传回来(用 uni.navigateTo)

插件使用

❗❗❗回调函数里面如果需要用到 this 记得该回调函数一定得写成箭头函数

存储

要记得 JSON.stringfy 再存储

uni.setStorageSync(app_user_timestamp, JSON.stringify(Date.now())) //设置时间戳

uniapp FormData 形式的参数得更改请求头

if (isFormData) _header['Content-Type'] = 'application/x-www-form-urlencoded'// 传递的参数是对象

对象

对象一整个赋值会改不到数据,要用 . 来更改属性值

搜索定位功能

uni.pageScrollTo({scrollTop: this.$refs[res.Data.BillInfo.BillNo][0].$el.offsetTop-310,duration: 0});

v-for涉及到增删改查时一定好设置一个唯一的id❗

公共的变量/函数/组件写在hooks.js里面

使多个地方可用到,复用性极强

一整个对象赋值改不到原始的对象,而是直接改了对象的数组

  • 要是想改掉原来对象的属性值,则需要:

  • for (let key in this.bjFormFields1) {this.bjFormFields1[key] = this.rowData[key]}
    

请求接口报错时,看看是不是多了个id的属性,这样有时会报错

❗computed要实现一定要在script里面用或者在视图里面用,不要然会不起作用!!!

vue2对象和数组变化一定要符合(数组:增删改查,对象:.xx = )规则才能有响应式,才可以正常进行计算以及watch

涉及到 ref 一定要注意有无 v-if(初始没有渲染dom)

样式

.out{background-image: linear-gradient(135deg, #b78666ff 16%, #ffe6d5ff 10%, #fff);background-size: 80% 100%;background-repeat: no-repeat;padding: 6px;.in {border-left: 4px solid #fff;padding-left: 8px;color: #fff;}}

前端技巧总结---持续更新相关推荐

  1. Androidstudio 最权威使用技巧, 持续更新

    #Androidstudio 3. 1. 1 的使用技巧, 持续更新 # ##快捷键部分 快捷键 作用 备注 Ctrl+N 快速检索并打开工程项目中的任何一个.java文件 Ctrl+shift+N ...

  2. tp5 使用技巧(持续更新中...)

    tp5 使用技巧(持续更新中...) 1.自动写入时间 create_time和update_time 使用save方法才行,insert方法不生效,不知为何 2.过滤字段 allowfield和st ...

  3. IDEA—使用技巧总结 [持续更新... ...]

    引言   在使用IDEA进行开发时,有时候会忘记一些常用的设置或者常用的命令方式,为了更好的便捷使用,进行常规使用总结.持续更新- - 分屏编辑对比当前类 双击所选择类名,打开当前类 右击选择[Spl ...

  4. JS高端奇淫技巧(持续更新)

    众所周知, JavaScript是一门很骚的语言, 写一句话有很多种表达方式, 语法怪异而风骚, 自由而散漫, 或许这就是JS成为最流行语言的原因吧. 本文收集了JS开发中常用的各种奇淫技巧, 一句话 ...

  5. 前端笔记 (持续更新~)

    目录 五星重点 1.git的使用 2.vue生命周期 3.vuex 4.vue组件通讯 5.前端性能优化 5.keep-alive的使用方法和生命周期 6.typescrpit 8.webpack 1 ...

  6. Word, PPT和Excel的常用技巧(持续更新)

    本文的目的是记录平时使用Word, PowerPoint和Excel的过程中的一些小技巧,用于提升工作效率. 此文会不定期的更新,更新频率完全取决于实际使用遇到的问题的次数. 目录 Word Powe ...

  7. LeetCode算法技巧汇总 -- 持续更新,学无止境!

    此篇是本人 LeetCode 算法刷题技巧总结,还包括刷过的算法题分类,自己记录以便后续二刷三刷,也分享给大家欢迎一起交流探讨.话说现在非常遗憾大学期间没能坚持搞 ACM,出来社会才越发觉得后悔,但是 ...

  8. 前端知识总结 持续更新

    目录 学习前端的第n天,总结一下学过的知识 1.HTML 2.CSS 3.JavaScript 4.其他部分 学习前端的第n天,总结一下学过的知识 1.HTML HTML5新特性 1.用于绘画的can ...

  9. 奇技淫巧-STL 库 ACM算法小技巧(持续更新中~~~)

    STL 库中的奇技淫巧 STL 是惠普实验室开发的一系列软件的统称,可以理解为一些容器的集合.STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件.STL 现在是C++的一部分,因此不用额 ...

最新文章

  1. Android Studio 的安装笔记
  2. 数据格式之战:JSON vs XML
  3. Arduino--AS608指纹传感器
  4. C#中的String类
  5. 在RedHat下安装MPlayer
  6. 流程控制示例:---3个实例示例:
  7. 游戏美术-魔兽世界查看器的正确使用方法
  8. pioneer dvr-xd50 固件_闲的蛋疼的验证:索尼 SONY WH1000XM3固件版本差异
  9. LabVIEW编程LabVIEW开发Thorlabs电机例程与相关资料
  10. 瑞斯康达olt排查故障的常用命令
  11. php仿qq空间网页源码,516 仿QQ空间网页头部代码
  12. android仿百度新闻,【Android】最新主流新闻app功能实现。仿网易,搜狐等新闻客户端实现展示...
  13. 如何重新修改VHDX硬盘大小?
  14. 问题解决:C# VS2010 调试程序出现:xxx.exe 中的 xxx 处有未经处理的异常: 0xC0000005: 写入位置 0x00000014 时发生访问冲突
  15. spring boot 项目 事务 不能回滚 代理(not eligible for auto-proxying)
  16. 可替换STM23G031的32位单片机
  17. 微信H5端网页授权流程(在H5中的openid获取,网页绑定微信)
  18. 垃圾邮件分类(trec06c数据集)数据处理-特征提取
  19. Linux添加http服务失败,Apache Web服务器配置http2各种失败
  20. 2022-11-28-大数据可视化“可视化国产/进口电影票房榜单”分析,特征维度大于50

热门文章

  1. opencv打开摄像头和视频文件
  2. H3C无线控制器AP license共享配置
  3. nginx报错问题记录
  4. matlab 狄利克雷函数代码,狄利克雷函数
  5. 【PTA】6-4 奇数值结点链表
  6. 【滴滴出行】2017秋招笔试真题(智力题)
  7. %大赛D--链式前向星+SPFA(BFS)+各种数据类型+各种最短路复习
  8. 机器学习总结(九):梯度消失(vanishing gradient)与梯度爆炸(exploding gradient)问题
  9. 海外权威媒体好评连连,一加5T中国11月28号发布
  10. 【2022 CCPC 华为云计算挑战赛】1005 带权子集和 (NTT 优化dp)