hsingyin / hsingyin.site Goto Github PK
View Code? Open in Web Editor NEW日常踩坑记录,日记型个人博客
日常踩坑记录,日记型个人博客
写某些弹窗组件,会出现这样的问题,安卓上没有问题,iOS就会出现滚动穿透的问题。
比较简单的解决方式,参考vant的popup
组件写法,可以在弹窗显示的时候在body上加样式。
overflow: hidden !important;
弹窗关闭的时候,去除这个样式,就可以了。
很直接的想法 路由守卫里取路由名字然后赋值给title
Vuejs 单页应用在iOS系统下部分APP的webview中 标题不能通过 document.title = xxx 的方式修改
这里参考了vue-wechat-title 源码修改了一下写法,引入一个iframe 触发微信浏览器title更新,然后移除iframe
router.js中
{
path: '/userCenter',
name: 'userCenter',
component: userCenter,
meta: {
title: '我的'
}
}
路由守卫中
document.title = to.meta.title || ''
var mobile = navigator.userAgent.toLowerCase()
if (/iphone|ipad|ipod/.test(mobile)) {
var iframe = document.createElement('iframe')
iframe.style.display = 'none'
var iframeCallback = function () {
setTimeout(function () {
iframe.removeEventListener('load', iframeCallback)
document.body.removeChild(iframe)
}, 0)
}
iframe.addEventListener('load', iframeCallback)
document.body.appendChild(iframe)
}
})
你肯定遇到上传图片的业务场景,你会需要对用户上传的图片做限制,文件类型,文件大小,但是如果限制死了文件大小,必然会带来糟糕的用户体验,现在通常的做法是对用户上传的原图做一次压缩减小体积后再上传。
// 入参就是需要压缩的图片文件(file类型)
compressImg(file) {
// 读取上传的图片文件
let reader = new FileReader()
let img = new Image()
reader.readAsDataURL(file)
reader.onload = e => {
img.src = e.target.result
}
// 准备好canvas画布
let canvas = document.createElement('canvas')
let context = canvas.getContext('2d')
let res = ''
// img加载好的回调方法
img.onload = () => {
const originWidth = img.width
const originHeight = img.height
// 最大尺寸限制
const maxWidth = 400, maxHeight = 400
// 目标尺寸
let targetWidth = originWidth, targetHeight = originHeight
// 图片尺寸超过400x400的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth
targetHeight = Math.round(maxWidth * (originHeight / originWidth))
} else {
targetHeight = maxHeight
targetWidth = Math.round(maxHeight * (originWidth / originHeight))
}
}
// canvas对图片进行缩放
canvas.width = targetWidth;
canvas.height = targetHeight;
// 清除画布
context.clearRect(0, 0, targetWidth, targetHeight);
// 核心JS就这个
context.drawImage(img, 0, 0, 400, 300)
// 转base64
// res = canvas.toDataURL("image/png")
// this.filesArr.push(res)
// 转blob
canvas.toBlob((blob) => {
// blob转回file
let _file = new File([blob], file.name, {type: file.type, lastModified: Date.now()})
// 加入文件预上传列表(这里加你的处理逻辑)
this.filesArr.push(_file)
})
}
}
展码这样的需求场景十分常见,在二维码生成之后需要根据移动设备的宽高写自适应。但是问题来了,使用到的qrcodejs2,构造函数传入的宽高不是rem这样的单位。canvas的画布大小是固定的。为此使用曲线救国在生成二维码的节点下加入important样式。
img,
canvas {
width: 3.8rem !important;
height: 3.8rem !important;
}
这样就可以实现二维码的自适应。
前一阵子,开发了某个vue
项目在iOS10
的H5表现和预期的不一致,出现了白屏的情况。打开vconsole查看发现报了个错误:SyntaxError: Cannot declare a let variable twice: 'e'.
重复定义了变量?打开查看代码估计会有这么一段
let e = e => {
console.log(e);
for (let e of [1, 2, 3])
console.log(e);
};
很显然这个e
不是人为定义变量,是打包的时候做的混淆和替换,这个怎么就出问题了呢?搜索引擎给出了答案,这是一个iOS10的BUG。
We incorrectly throw a syntax error when declaring a top level for-loop iteration variable the same as a parameter
当你定义一个与参数同名的for循环迭代变量时,我们错误地认为这是一个语法错误。
加之我用的是旧版本的vue-cli,才出现的问题。
解决方法如下:
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
},
mangle: {
safari10: true
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
再次build就不会有问题了。
感谢张京写的文章《假如测试说你的网站在iOS 10有问题》
假定需求是列表中只能包含10块钱以下的食物。
当你开心的写一个下拉列表并且想做一个条件渲染的时候你可能会有这么直接的写法:在v-for
中加v-if
// 你的数据
options: [
{
name: '子母粉丝',
value: 18
},{
name: '红烧牛肉面',
value: 28
},{
name: '瓦罐小炒',
value: 13
},{
name: '炒面',
value: 8
}
]
<!-- 你的下拉组件 -->
<el-select v-model="value" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.name"
:label="item.name"
v-if="item.value < 10"
:value="item.value">
</el-option>
</el-select>
到这里你实现了这个需求,不过其实很大概率你的eslint会警告你,这也是Vue官方不推荐的写法,参考链接
当 v-if
与 v-for
一起使用时,v-for
具有比 v-if
更高的优先级,实际上我们浪费了一些性能在不必要渲染的数据项上,我们可以通过计算属性例如 optionsIsCheap
来代替原本的数据源 options
,计算属性返回一个过滤后的列表。
optionsIsCheap() {
return this.options.filter(item => item.value < 10)
}
改写之后大概是这个样子
<!-- 你的下拉组件 -->
<el-select v-model="value" placeholder="请选择">
<el-option
v-for="item in optionsIsCheap"
:key="item.name"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
微信小程序开发暂时采用了是
mpvue
框架,开发时遇到了一些坑,记录一下防止遗忘。
当你跳转(使用navigateTo
)的时候页面上的data会被缓存,所以在onShow
或者onLoad
钩子函数最好做个初始化。特别是你写了定时器等。
必须npm run dev
一下,否则微信开发者工具会报错
模板里面的写法不支持过滤器,函数表达式,用计算属性或者别的代替
这个只能说你不能用特别大的背景图写在css
里的background
里,取而代之写image
标签,注意压缩一下图片节省空间
和微信小程序原生支持的一些API
,比如获取用户手机号信息,需要一个button
去调用
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
你要改写成以下这种,用@
代替bind
<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber"></button>
不支持对象写法
不支持插槽传递变量的写法,建议props代替
手机预览PDF经常被产品提出,H5、小程序均需要展示PDF的需求,稍微整理一下。
在不依赖插件的情况下,用个iframe大法。iOS可以打开PDF的链接直接预览查看,安卓则会跳到浏览器拉起下载。两端的体验不太一致。
<!--PDF查看器-->
<template>
<iframe :src="src" class="pdf-viewer"></iframe>
</template>
<script>
export default {
data() {
return {
src: this.$route.query.pdfUrl
}
}
}
</script>
<style lang="less">
.pdf-viewer {
border: 0;
position: relative;
min-height: 100vh;
width: 100%;
}
</style>
使用插件可以尝试pdfh5 、vue-pdf,可以获得iOS和安卓两端体验一致的良好体验情况。
小程序里查看PDF也和H5上打开PDF的情况一样,iOS和安卓需要区别对待。iOS可以直接在webview组件预览,安卓则下载后打开。iOS你同样可以下载再打开,不过直接webview组件预览体验更好。
// 这边在onLoad(options)调用init方法
init(options) {
this.viewPdf(options)
},
async viewPdf(options) {
// 这边对平台的相关api做了封装并挂载到原型上
this.$api.showLoading()
// 获取系统信息,这里是用promise包了一层微信的wx.getSystemInfo
const res = await this.$api.getSystemInfo()
this.systemInfo = res.system
const isAndroid = /android/i
if (!options.webUrl) {
console.log('未携带参数')
this.$api.hideLoading()
return false
}
if (isAndroid.test(this.systemInfo)) {
console.log('Android')
wx.downloadFile({
url: options && options.webUrl,
success: (res) => {
console.log(res)
const Path = res.tempFilePath // 返回的文件临时地址,用于后面打开本地预览所用
this.$api.hideLoading()
wx.openDocument({
filePath: Path,
success: function (res) {
console.log('打开成功')
}
})
},
fail: (res) => {
this.$api.hideLoading()
this.$api.showToast({
title: '下载失败'
})
console.log(res)
}
})
} else {
console.log('iOS')
let _webUrl = options && options.webUrl
// 传递参数的时候需要encodeURIComponent一下防止参数截断
_webUrl = decodeURIComponent(_webUrl)
if (_webUrl) {
this.webUrl = _webUrl
}
this.$api.hideLoading()
console.log(this.webUrl)
}
}
升级了vue-router v3.1.6
,加了路由守卫,判断没有携带token就指向登录页,强迫症患者看着控制台打出了一堆Uncaught (in promise) undefined
十分难受。
在vue-router v3.0.7
之后push和replace返回的是promise不是回调,如果遇到路由守卫的next指定到某个页面(例如登录页面),需要主动catch
这个promise
的reject
。[issue2881] (vuejs/vue-router#2881 (comment)) 里posva给出了比较详细的回答和解决方案。
this.$router.push({
name: `${name}`
}, () => {})
// or
this.$router.push({
name: `${name}`
},
onComplete => {
console.log('完成')
},
onAbort => {
console.log('哦打断了')
})
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
{
"singleQuote": true,
"semi": false,
"tabWidth": 2
}
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
format_on_save = true
在低版本的Android
或者iOS
设备下,H5会出现白屏的现象,打开控制台发现报错了许多错误。(这里针对vue-cli2.X
项目)
原因是Android 6.0
和iOS 10
以下对ES6
新语法不兼容,现在低版本的系统在市场上仍有一部分占比,虽然不想兼容但是莫得办法
babel-polyfill
babel-polyfill
、es6-promise
main.js
中引用babel-polyfill
、es6-promise
import 'babel-polyfill';
import Es6Promise from 'es6-promise';
require('es6-promise').polyfill();
Es6Promise.polyfill()
.babelrc
文件{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime",["import", {
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}]],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node",["import", {
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}]]
}
}
}
js
是否用了高级语法(因为babel
会忽略node_modules
,导致依赖包中的ES6
语法无法被转换)vant
、sm-crypto
依赖包有高级语法需要转换向后兼容,配置build/webpack.base.conf.js
// build/webpack.base.conf.js
entry: {
app: ["babel-polyfill", "./src/main.js"]
},
...
{
test: /\.js$/,
loader: 'babel-loader',
include: [
resolve('src'),
resolve('test'),
// 将需要转译的模块包括进来
resolve('node_modules/sm-crypto'),
resolve('node_modules/vant'),
resolve('node_modules/webpack-dev-server/client')
]
}
static/js/serviceConfig.js
(因为不会被编译)里面的一些变量使用的模板字符串要改成通常的写法,let
、const
也得换成var
好久没写issue
了,目前淹没在搬砖业务中,想想还是要整理一下遇到的问题和解决方法。我们公司目前用mpvue
来构建小程序,taro
+ts
的方案目前还没大面积采用。为了项目的“稳定”,mpvue
大法先上。
微信小程序的实名接口申请比较繁琐和复杂,且不一定能申请下来。所以目前获取用户信息我们通常取巧的使用微信的auto-fill
(自动填充)能力快速填写用户的三要素。
使用mpvue写页面逻辑时,如果我们单纯只是在input标签增加auto-fill属性,会遇到视图有回填数据,但是在输入框上v-model的data没有成功赋值绑定的神奇效果。
我们观察一下官方示例:
<form bindsubmit="submit">
<input class="weui-input" placeholder="姓名" auto-fill="base_info.name" />
<input class="weui-input" placeholder="手机" auto-fill="phone_info.phone" />
<input class="weui-input" placeholder="身份证" auto-fill="base_info.id_card_num" />
<picker placeholder="住址" auto-fill="address_info.address" />
<button form-type="submit">submit</button>
</form>
项目针对input
做了组件封装,通常的想法是增加props
传入auto-fill
属性,但是实践发现这样无法拉起自动填充。form
内部的button
也不能加click
,转由form
的bindsubmit
(mpuve
里面写法变成@submit
)去调用函数。最后采用了单独封装带有auto-fill
属性的input
组件解决了问题,简单粗暴的解决方案。
随着之而来的是打脸,虽然可以正常使用项目封装的input
组件拉起自动填充,但是点击button
提交的时候,并没有获取到form
内部input
的值,而且就算通过change
事件监听输入框的值,也只会监听到当前输入框的变化,但是自动填充是点击之后会把当前页面所有带自动填充属性的input
都赋值,所以还需要外层form
的submit
回调函数在点击button
的时候获取表单内的数据,通过一番检查后发现input
组件中input
标签缺少了name
属性,导致了外层form
无法拿到数据,添加之后就喜闻乐见的可以拿到data数据
form
表单包在外层,且用带有form-type
为submit
的button
去触发form
的submit
事件,button
自身不写click事件input
组件直接传入props
动态渲染auto-fill
属性无法拉起自动填充,需要单独封装带有auto-fill
属性的input
组件,或者直接使用input
标签。同样无法动态渲染的还有type
属性。input
组件必须添加name
属性,否则在外层form
的submit
方法无法拿到表单内input
输入框的值form
表单的submit
回调函数可以拿到input
输入框的值进行赋值操作A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.