Uniapp手机上运行的测试服一直弹出热更提示并且更新完重进还是会有热更提示运行包的应用版本不对将mainifest的应用版本名称和版本号改为线上最新版本即可为什么.gitignore 忽略了 unpackageSourceTree 还显示该目录的未暂存文件1. 项目初始化时你还没写.gitignore文件就直接执行了「第一次 git commit」→ 此时 Git 会把项目里所有文件 / 文件夹都默认加入追踪其中就包含了unpackage之后你再补写/unpackage/到.gitignore已经晚了2. 开发中误操作曾经手动在 SourceTree 里勾选了unpackage文件夹执行了「暂存」或「提交」操作导致它被 Git 记录为「需要追踪的目录」。解决办法打开项目根目录的终端vscode 终端 / 系统 cmd 都可以依次执行下面 2 行命令无需任何修改直接复制粘贴确保在执行命令前没有暂存的文件小心被一起提交# 第1行核心命令移除Git对unpackage文件夹的「追踪标记」本地文件保留不变 git rm -r --cached unpackage # 第2行把「移除追踪」这个操作提交到Git让忽略规则永久生效 git commit -m 移除unpackage的git追踪启用.gitignore忽略规则预防方法1【项目初始化第一优先级】新建项目后第一件事就是创建并编写.gitignore文件写完后再执行任何git add / git commit操作这是黄金法则99% 的忽略失效问题都是因为「先提交后写.gitignore」导致的。Git 的逻辑是「先到先得」先提交的文件会被追踪后加的规则无效。2永远不要把「自动生成的产物目录、依赖目录」提交到 Git 仓库比如 uni-app 的unpackage、所有前端项目的node_modules、打包后的dist、缓存文件、日志文件等这些都是「可重新生成」的提交了只会添乱还会让仓库体积变大。3.gitignore写好后一定要「提交到 Git 仓库」.gitignore本身是一个普通的文本文件只有把它提交到仓库团队协作时其他成员拉取项目后才能复用你的忽略规则避免团队其他人也踩同样的坑。uni-app 项目 .gitignore 标准完整版# 第三方依赖包 /node_modules # uni-app 编译构建产物目录 /unpackage/ # 编译缓存文件 .DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? # 本地配置文件比如自己的环境变量、隐私配置 /local_config.js /.env.local /.env.development.local /.env.production.local # npm 日志文件 npm-debug.log* yarn-debug.log* yarn-error.log*tabBar跳转uni.navigateTo和uni.redirectTo只能跳转应用内非 tabBar 的页面的路径 ,所以一个页面如果绑定了tabBar页面上的navigator 的opentype为navigate或redirect则跳转相应的页面就无效了v-bind在绑定stylev-bind在绑定style的时候,一直用双引号包裹单引号很麻烦并且不方便扩充所以可以把属性值当作对象来处理view classbox1 :stylebackground-color: ${bgcolor}/view !-- 效果与上面一样注意命名格式-要替换成大写字母 -- view classbox1 :style{backgroundColor: bgcolor}/viewdata() { return { bgcolor:yellow } }v-bind绑定纯字符串记得带单引号,不然会被当成变量view :title普通字符串/view运行到android和ios制作自定义底座如果想运行到手机需要提前创建自定义调试基座基底打包完成后就可以运行到手机选择运行到对应基座nvue与vue的区别nvue与vue有区别例如nvue中文字内容必须用text组件nvue 页面只能使用flex布局不支持其他布局方式等详情见页面 | uni-app官网uniapp真机调试安卓uniapp真机调试安卓点击运行--运行到手机或模拟器--显示webview调试控制台点击运行--运行到手机或模拟器-运行到基座控制台会出现webview调试模块点击箭头就会出现控制台width超出borderwidth: 100%; padding: 10rpx; // 当width为100%并且有padding的时候,可以看到大小会往右移, // 这时候加box-sizing可以把padding变为内填充 box-sizing: border-box; //ps:nvue盒模型的 box-sizing 默认为 border-box //即盒子的宽高包含内容、内边距和边框的宽度不包含外边距的宽度computed使用computed的每一个计算属性都会被缓存起来只要计算属性所依赖的属性发生变化计算属性就会重新执行视图也会更新。下面代码中计算属性demo它依赖了text和title这两个属性只要它们其中一个属性变化demo就会重新执行。computed计算属性会被缓存在下面代码中使用了两次demo但在控制台只输出了一次 “this.title this.text”。input typetext v-modeltitle / text{{title}}/text view---------------------/view text{{demo}}/text text{{demo}}/text ... data(){ return{ title: sada, text: 一一一, } }, ... computed: { demo() { console.log(this.title this.text) return this.title this.text } },自定义事件1.创建自定义组件以及接收自定义属性在这个目录中新建组件组件pubTitle.vue内容template view classpubTitle view classtime {{time}} /view view classbig {{title}} /view view classsmall {{subtitle}} /view view classsmall {{list}} /view view classsmall {{user}} /view view classline /view /view /template script export default { name: pubTitle, //props:类似data()调用的时候给title赋值即可 //接受自定义属性不带默认值 // props: [title, subtitle], // 或者这样可以给属性赋值一个默认值 //其他页面调用的时候如果没给属性赋值则会显示默认值 props: { title: { type: String, default: 默认标题 }, subtitle: { type: String, default: 默认副标题 }, time: { type: Number, default: Date.now() }, list: { type: Array, default () { return [1, 2, 3] } }, user: { type: Object, default () { return { name: 匿名, gender: 保密 } } } }, data() { return { }; } } /script style langscss .pubTitle { padding: 60rpx 30rpx; text-align: center; background: #95E1D3; .big { font-size: 50rpx; font-weight: 600; color: #333; } .small { font-size: 28rpx; color: #888; } .line { display: inline-block; width: 80rpx; height: 8rpx; background: #1AA034; border-radius: 10rpx; } } /style其他页面调用组件只要用组件名标签并且给组件的props中的属性赋值即可//index.vue template view //标题文本内容为“首页” pubTitle title首页 subtitleindex page/pubTitle //标题内容为“forTest” pubTitle :titletitle subtitlefor page/pubTitle //不传值则组件文本内容是默认标题和默认副标题 pubTitle/pubTitle pubTitle :timetime subtitlefor page/pubTitle pubTitle :time987 subtitlefor page/pubTitle pubTitle :list[4,5,6] subtitlefor page/pubTitle pubTitle :listlist subtitlefor page/pubTitle pubTitle :useruser subtitlefor page/pubTitle pubTitle :user{user:李四,sex:女} subtitlefor page/pubTitle /view /view /template ... data(){ return{ title: forTest, time: 123, list: [9, 9, 9], user: { name: 张三, gender: 男, }, } }2.emit子向父传值template view !-- 我是子组件myevent -- {{title}} view class input typetext placeholder请输入.. inputoninput / /view {{array}} /view /template script export default { name: myevent, props: { title: { type: String, default: 111, }, array: { type: Object, default () { return { name: 张三, age: 12, } } } }, data() { return { }; }, methods: { oninput(e) { let a 子组件传入 e.detail.value this.array.name a //创建自定义事件用于引用该组件的父组件调用事件名myenv后面是返回 this.$emit(myenv, this.array) } } } /script style langscss /style!-- 我是父组件 -- !-- 使用自定义方法myenv 类似click-- myevent title组件间的传值 myenvonmyenv/myevent ... methods: { // 绑定子组件的自定义方法接收其返回值 onmyenv(e) { console.log(e); } }3.组件中使用原生方法!-- 我是父组件 -- //在组件中使用click等原生方法需要带.native不然会以为是子组件自定义方法导致无法实现功能 myevent title组件间的传值 myenvonmyenv click.nativeonClick()/myevent ... onClick() { console.log(12) }4.sync关键字当一个子组件改变了一个prop的值时这个变化也会同步到父组件中所绑定。.sync它会被扩展为一个自动更新父组件属性的v-on监听器。//父组件 mypop :state.syncstate/mypop ... data() { return { state: false }; },//子组件 ... button clickonClose()关闭/button ... methods: { onClose() { //改变父组件的state值, // 添加update:父组件就可以用.sync关键字直接获取state的值 //就不需要在父组件中重新写个方法来接收state的值了 this.$emit(update:state, false) } }, props: { state: { type: Boolean, default: false }, }for循环中btn点击变色使用this.isChangecolor[e - 1] e 用这种方式给isChangecolor添加元素无效 的原因是Vue无法检测到直接通过索引设置数组项的变化如this.items[index] newValue。Vue的响应式系统需要特殊的方法来触发视图更新。//for循环内的btn通过判断isChangecolor的index位置是否有值来更改第index个btn的颜色 button classbtn :classisChangecolor[index-1]index?changeBg: clickgoBuy(index) 28.00/button //script data() { return { isChangecolor: [], } }, goBuy(e) { // this.isChangecolor[e - 1] e 用这种方式给isChangecolor添加元素无效改为用$(set) this.$set(this.isChangecolor, e - 1, e) console.log(this.isChangecolor, this.isChangecolor[0]); } //css .btn { width: 150rpx; height: 50rpx; font-size: 25rpx; line-height: 50rpx; border-radius: 47rpx; background: linear-gradient(90deg, #FCC334 0%, #FBEF9B 100%); .changeBg { background: #fff; } }web-view在云服务器上部署了cocos小游戏之后想要显示在uniapp项目中并且实现与uniapp的信息传输就需要web-view组件cocos部分下载uni.webview.1.5.6.jsuni-app/dist/uni.webview.1.5.4.js · DCloud/uni-app - AtomGit | GitCode创建构建模板找到构建模板文件夹通常是 build-templates/web-mobile/index.html如果没有就从 build/web-mobile/index.html 复制一份或者直接修改构建后的文件在index.html的body中引入构建后记得把 uni.webview.1.5.5.js 文件放到构建目录里和 index.html 同级!-- 引入 uni-app 的 SDK -- script typetext/javascript src./uni.webview.1.5.5.js/script script document.addEventListener(UniAppJSBridgeReady, function() { console.log(UniApp JS SDK Ready); // 这里可以通知游戏 SDK 加载完毕但通常不需要 }); /scriptcocos在游戏结束面板弹出时init 方法中向 UniApp 发送消息。init(score: number, bestScore: number) { ... // ----------------------------------------------------------- // 将分数发送给 UniApp // ----------------------------------------------------------- this.sendScoreToUniApp(score, bestScore); } /** * 发送数据给 UniApp */ sendScoreToUniApp(score: number, bestScore: number) { // 检查环境避免在编辑器或普通浏览器报错 // ts-ignore: 忽略 ts 对 window.uni 的类型检查 if (window.uni window.uni.postMessage) { console.log(Cocos: 向 UniApp 发送分数); // uni.postMessage 的格式必须是 { data: {} } // ts-ignore window.uni.postMessage({ data: { action: updateScore, // 消息类型标记 currentScore: score, bestScore: bestScore } }); } else { console.log(Cocos: 当前非 UniApp 环境无法发送消息); } }Cocos 构建与部署在 Cocos Creator 中点击构建 (Build)。平台选择Web Mobile。构建完成后将构建生成的文件夹假设叫 web-mobile重命名为 2048game名字随意。关键步骤将整个 2048game 文件夹复制到 UniApp 项目的 /hybrid/html/ 目录下。UniApp 规定本地 HTML 必须放在 /hybrid/html/ 才能被 web-view 加载。路径结构应为你的UniApp项目/hybrid/html/2048game/index.html。或者把2048game部署到云服务器上这样在h5上也能看到画面使用本地路径在浏览器打开会报错uniapp部分template view classcontainer !-- 顶部展示区显示从Cocos传回来的分数 -- view classinfo-bar textUniApp本地最高分: {{ savedBestScore }}/text /view !-- 嵌入 Cocos 游戏 -- !-- src 指向本地的 index.html -- !-- message 用于监听 Cocos 发来的 uni.postMessage -- web-view classgame-view src/hybrid/html/2048game/index.html messagehandleMessage:webview-styleswebviewStyles :update-titlefalse /web-view /view /template ...... data() { return { savedBestScore: 0, webviewStyles: { width: 430px, height: 650px, } // 别忘了这个样式 }; }, ...... onLoad() { // 1. 页面加载时先从本地缓存读取旧的最高分 const score uni.getStorageSync(MY_2048_BEST_SCORE); if (score) { this.savedBestScore score; } // 如果是 H5 环境手动监听 window message // #ifdef H5 window.addEventListener(message, this.handleH5Message); // #endif }, // onUnload() { // #ifdef H5 window.removeEventListener(message, this.handleH5Message); // #endif }, methods: { /** * 处理来自 Cocos 的消息 */ handleMessage(evt) { console.log(【App端】收到消息:, evt.detail); // 注意evt.detail.data 是一个数组 const dataList evt.detail.data; if (dataList dataList.length 0) { const msg dataList[dataList.length - 1]; // 取最新一条 this.processLogic(msg); } // 现在运行到app上会报错,解决办法是把游戏部署到服务器上使用http/https协议 // 本地方案必须修改代码 手动注入一段代码用 XMLHttpRequest (XHR) 来“欺骗”浏览器替换掉不兼容的 fetch。 }, /** * 情况2H5 端通过 window.message 触发 */ handleH5Message(evt) { console.log(【H5端】收到消息:, evt.data); // H5传过来的直接就是数据对象可能包裹在 data 里 const msg evt.data evt.data.data ? evt.data.data : evt.data; console.log(msg1, msg); this.processLogic(msg.arg); }, /** * 统一处理逻辑 */ processLogic(msg) { if (msg msg.action updateScore) { console.log(成功提取最高分:, msg.bestScore); this.savedBestScore msg.bestScore; uni.setStorageSync(MY_2048_BEST_SCORE, msg.bestScore); // 提示一下用户 uni.showToast({ title: 分数已同步, icon: success }); } } }注意点1.uni.postMessage 在H5 浏览器环境下即用浏览器预览 UniApp通常是不生效的或者行为与 App 不一致。强烈建议使用真机调试连接手机运行基座或者使用 App 模拟器。h5环境访问会有跨域问题想在h5上看可以通过 window.message 触发2.app的vue中 web-view的属性只能用webview-styles控制不受class属性的影响并且webview-styles只有宽高和loading三个属性并且会自动铺满除去原生导航栏之外的所有区域并且是最高层级不好调整样式解决办法app的web-view放在nvue中.vue 页面里的 web-view 是原生图层不受 CSS 控制。.nvue 页面Weex 引擎里的 web-view 是一个普通组件它完全支持 flex 布局你可以像排列两个 div 一样排列 info-bar 和 web-view。3.web-view的src用本地的src如果想用浏览器查看会报错csshover-class与position父元素使用“hover-class”属性修改scale的时候的时候子元素如果设置了定位position可能会导致按压事件区域可能异常使用时需要注意一个元素添加不同的class的样式覆盖view class a b实际宽度是200px因为在style中b比a后写所以b会覆盖掉a/view style .a{ width:100px; } .b{ width:200px } /stylenvue中view使用了hover属性导致点击按钮之后按钮位置偏移一、偏移的核心原因1.hover 样式修改了盒模型属性如果 hover 时改变了padding/margin/width/height等盒模型属性nvue 原生渲染引擎会实时重排布局 —— 比如 hover 时给按钮加了padding: 10rpx点击后样式未及时恢复或原生布局计算延迟导致按钮位置偏移。2.transform: scale 导致的视觉 / 布局偏移若 hover 用了transform: scale()做缩放效果nvue 中transform的锚点默认是元素中心缩放后可能因父容器的flex/absolute布局导致元素视觉位置 “错位”若缩放后未及时重置比如touchend事件延迟会残留缩放状态表现为位置偏移。3.nvue 对 hover-class 的兼容性问题nvue 原生渲染对hover-class的支持不完善尤其是结合position: absolute/fixed时hover 触发的样式可能导致原生视图的布局计算误差出现偏移。4.事件触发顺序与样式恢复延迟手动用touchstart加 hover 样式和touchend恢复样式模拟 hover 时若touchend触发延迟比如有事件冒泡 / 阻止默认行为会导致样式恢复不及时看起来像位置偏移。层级调试在ios的nvue中调试层级的时候碰到了一个问题同一个父容器先写子容器的代码z-index3后面添加的组件的z-index9按道理来说组件的层级要比子容器的层级高但是实际情况是组件层级在子容器之下原因子容器的position是fixed组件的position是absolute,解决方法组件的position修改为fixed即可显示在子容器上ai分析你前面的view结构所在的父容器设置了position: fixed而组件positionFourBtn是position: absolute。在 nvue 原生渲染逻辑中position: fixed的容器及其子元素原生层级优先级高于同一父容器下的absolute元素即使组件z-index更高且 DOM 中先出现的fixed相关元素会被原生引擎优先渲染为 “更高层级视图”后出现的absolute组件自然被覆盖background-image要记得添加属性使用background-image的时候开发时能点看图片说明路径是对的但运行后没显示可能是样式属性缺失导致图片被隐藏图片尺寸远大于元素尺寸且未设置background-size导致只显示空白缺少background-repeat或background-position图片重复或偏移出可视区域.cItem { width: 100rpx; height: 100rpx; background-image: url(/static/wenzibj.png); background-size: 100% 100%; // 让图片铺满元素 background-repeat: no-repeat; // 禁止重复 background-position: center; // 居中显示 }JavaScriptJavaScript 数组引用赋值问题要copy数组的时候可以用...展开运算符 ,.slice(),Array.from() 这些浅拷贝或者深拷贝let a [1, 2, 3]; let b a; // 这里不是创建新数组而是将b指向a的引用 b.push(4); // 通过b修改了a引用的数组 console.log(a); // [1, 2, 3, 4] ← a也被改变了 ----------------------------------------------- let a [1, 2, 3]; let b a.slice(); // 方法1使用slice创建新数组 // 或 let b [...a]; // 方法2使用展开运算符 // 或 let b Array.from(a); // 方法3 b.push(4); console.log(a); // [1, 2, 3] ← 保持不变 console.log(b); // [1, 2, 3, 4] --------------------------------------- const a [[1], [2], [3]]; const b JSON.parse(JSON.stringify(a)); // 深拷贝浅拷贝与深拷贝特性浅拷贝深拷贝复制深度只复制第一层属性/元素递归复制所有嵌套层级内存引用嵌套对象/数组保持原引用所有层级都是全新的独立副本修改影响修改嵌套内容会影响原对象修改任何内容都不会影响原对象性能快(只复制一层)慢(需要递归复制所有层级)内存占用较少(共享嵌套对象)较多(完全独立副本)原对象: { name: 张三, age: 25, address: { city: 北京, street: 长安街 } } 浅拷贝后: { name: 张三, ← 新值 age: 25, ← 新值 address: { ← 仍然是原对象的引用! city: 北京, street: 长安街 } } 深拷贝后: { name: 张三, ← 新值 age: 25, ← 新值 address: { ← 全新的对象! city: 北京, street: 长安街 } }.map(Number)let digits [1, 2, 3] let str for (var a 0; a digits.length; a) { str str digits[a] } //map() 会对数组的每个元素调用提供的函数并返回一个新数组。 //Number 是一个内置函数用于将值转换为数字。 //所以 map(Number) 相当于 //const numberArray stringArray.map(item Number(item)); return (Number(str) 1).toString().split().map(Number)两种防抖函数//在工具类中添加方法 //第一个防抖函数通过setTimeout计时器防止玩家频繁点击按钮 let debounceTimeOut null function debounceFunc(func, wait 2500, notShowTip) { if (debounceTimeOut ! null) { if (!notShowTip) { uni.showToast({ title: 请稍候进行操作, icon: none, duration: 2000 }); } return } if (typeof func function) { debounceTimeOut setTimeout(() { clearTimeout(debounceTimeOut); debounceTimeOut null; }, wait); func(); } } //第二个防抖函数根据点击时间差来判断是否点击多次 let oldTime 0 let newTime 0 function debounceFunc2(func, wait 1500, notShowTip) { newTime Date.now(); if (newTime - oldTime wait) { oldTime newTime; if (!notShowTip) { uni.showToast({ title: 请稍候操作, icon: none, duration: 2000 }); } return } oldTime newTime; if (typeof func function) { func(); } } ... //记得导出函数 export { debounceFunc, debounceFunc2, }v-for的key最好不要直接用:key index,建议直接使用:key ”‘字符串’item.id(唯一标识符)“防止在冗长的代码中在同层级下出现两个index还不知道在哪找起Promise和async概念比喻核心作用适用场景Promise餐饮取餐号异步操作的“占位符”承诺未来会给你结果。封装setTimeout或uni.requestAsync声明“我是长跑选手”标记一个函数是异步的允许内部使用await。所有包含网络请求或定时等待的函数Await路障 / 定身雷暂停当前函数的执行死等结果回来再走下一行。需要拿接口数据后再做逻辑处理Promise.all并排跑百米同时发出多个请求等最慢的一个回来就统一结算。页面初始化同时加载列表、Banner、用户信息标准异步请求 (Try-Catch-Finally)这是最稳健的工业级写法。const handleRequest async () { loading.value true; // 1. 开始转圈 try { // 2. 阻塞等待等结果回来 const res await uni.request({ url: ... }); // 3. 成功后的逻辑 data.value res.data; } catch (error) { // 4. 容错网络断了或接口崩了 uni.showToast({ title: 加载失败, icon: none }); } finally { // 5. 闭环无论成败都要关掉转圈 loading.value false; } };性能优化 (Promise.all)当页面一打开需要调好几个接口时用这个。*数组里的每个成员必须是Promise对象onMounted(async () { try { // 三个请求并发总耗时 最慢的那一个 const [list, user, time] await Promise.all([ getListApi(), getUserApi(), getSystemTimeApi() ]); // 结构赋值一次性拿到所有数据 giftList.value list; userInfo.value user; serverTime.value time; } catch (err) { console.error(初始化页面失败, err); } });Promise.all的工作逻辑是检查数组里的每一个元素。如果是 Promise就等它状态变为resolved。如果数组里混进了一个不是 Promise的东西比如一个普通函数或数字Promise.all会认为它已经“瞬间完成了”不会产生任何等待效果。没有await的async是虚假的如果你不写await代码会一溜烟跑完不会等异步结果。await只挡住函数内部async函数内部在死等但它不会阻塞外面的同辈方法执行保证了 UI 不卡死。Promise.all是一票否决制数组里只要有一个请求 Reject失败整个Promise.all就会直接跳进catch。new Promise的本质一份“延期交付”的合同你可以把它想象成你和 JavaScript 签的一份合同“我现在开始干一件费时间的事干完了我拨动resolve开关干砸了我拨动reject开关。”const myTask new Promise((resolve, reject) { // 这里写“费时间”的代码比如定时器、网络请求、读文件 const success true; if (success) { resolve(想要传给后面的数据); // 拨动“成功”开关 } else { reject(报错信息); // 拨动“失败”开关 } });必须要拨动开关如果你在new Promise内部既没写resolve()也没写reject()那么外面的await就会永久死等下去直到浏览器崩溃。只能改一次状态一旦执行了resolve这个 Promise 的状态就锁死了。你后面再写reject也是没用的。立刻执行当你new Promise的那一刻内部的代码是立即开始运行的它不会等你调用await才开始。使用场景① 包装“老旧”的回调函数Promisify② 模拟延迟 / 强制等待③ 预加载资源如图片Bug报错报错了不要只看web 可以运行小程序看看page.json的错会在小程序编译的时候告诉位置web不会list.push()... list1: [1, 2], ... // 错误以为l1是新数组实际上l1是数字数组长度 let l1 this.list1.push(1); // 数组引用赋值问题实际上l2和list1指向的是同一个数组 let l2 this.list1 // this.list1也会改变 l2.push(1) // 使用展开运算符copy数组,再push就不会改变list1了 let l3 [...this.list1] l3.push(1)props 应该是单向向下传递的报错Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the props value. Prop being mutated: state这个错误是 Vue 的警告信息表明您正在直接修改一个 prop 的值这违反了 Vue 的单向数据流原则。state是作为 prop 从父组件传递下来的子组件中直接修改了this.state这违反了 Vue 的设计原则props 应该是单向向下传递的//父组件 button click.nativeonClick()开启/button mypop :statestate/mypop ... methods: { // 绑定子组件的自定义方法接收其返回值 onmyenv(e) { console.log(e); }, onClick() { this.state true } },//子组件 methods: { click() { this.state false // 直接修改了prop导致报错 } }, props: { state: { // 从父组件接收的prop type: Boolean, default: false } }大数精度丢失大数精度丢失是指 JavaScript 在处理非常大或非常小的数字时无法精确表示这些数字导致计算结果不准确的现象。JavaScript 使用IEEE 754 双精度浮点数标准来表示数字这意味着最大安全整数Number.MAX_SAFE_INTEGER 90071992547409912⁵³ - 1最小安全整数Number.MIN_SAFE_INTEGER -9007199254740991超过这个范围的整数会出现精度问题。let digits [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]; let str digits.join(); // 6145390195186705543 // 这个数字超过了 MAX_SAFE_INTEGER (9007199254740991) console.log(Number(str)); // 6145390195186705000 ← 精度丢失 // 最后三位 543 变成了 500解决方法使用 BigIntES2020// 在数字后面加 n 表示 BigInt const bigNum1 9007199254740992n; const bigNum2 9007199254740993n; console.log(bigNum1 bigNum2); // 18014398509481985n ← 精确 //字符转bigint并且做加法 let str6145390195186705543 BigInt(str) 1n //6145390195186705544n服务器云服务器安装宝塔购买完服务器可以先重置密码后启动实例的远程连接搜索宝塔面板复制宝塔linux安装脚本if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ssl251104按y同意后会开始安装等待5分钟左右会出现宝塔外网ipv4面板地址内网面板地址账号密码要记住并且提示请安全组放行“宝塔”端口在安全组的入方向添加对应的宝塔端口重启实例再复制外网地址到浏览器上即可看到宝塔面板把cocos文件放入云服务器在php项目中添加一个站点,文件放在宝塔的对应目录下云服务器和宝塔都放行对应的端口号重启云服务器后浏览器输入http://外网地址:端口号即可运行cocos游戏