19Y-04M: Swiper滑块绑定Vue点击事件失效问题。
使用Swiper 3.3.1做页面轮播,接口取到数据后创建Swiper实例,在滑块上绑定Vue点击事件@click,初始点击跳转生效,滑动或点击后不再生效。
解决办法:给滑块定义data-href属性传递url跳转地址,在Swiper实例属性onClick属性上获取地址后跳转。
公告区轮播DIV:
<div class="tip">
<i class="tip-laba"></i>
<div class="swiper-container" id="noticeSwiper">
<div class="swiper-wrapper">
<div v-for="(item, index) in data" :key="index" :data-href="item.url" class="swiper-slide" @click="goPage(item.url)">
<div class="tip-item">
<p class="txt">{{ item.title }}</p>
<i class="icon-arrow"></i>
</div>
</div>
</div>
</div>
</div>
let swiper = new Swiper('#noticeSwiper', {
initialSlide: 0,
direction : 'vertical',
paginationClickable: true,
slidesPerView: 1,
preventClicks: false,
speed: 1000,
autoplay: 3000,
autoplayDisableOnInteraction: false,
loop: data.length > 1 ? true : false,
onClick: (swiper, e) => {
this.goPage($(swiper.clickedSlide).data('href'))
}
})
20Y-04M1:Swiper滑块在荣耀畅玩4手机上下沉或不展示问题。
页面元素同上,外层元素(class="tip")设置了高度,但未给swiper元素设置高度:
.tip {
min-height: .7rem;
padding: .14rem .3rem;
background: #fffbf4;
}
解决办法:给Swiper设置高度
/*fix 荣耀4畅玩轮播公告文字不出现兼容bug*/
.tip .notice-swiper{
height: .7rem;
}
20Y-04M2:background-size在ISO和Android上表现不一致问题。
<p>
<i class="doc-video doc-audio"></i>文本内容
</p>
当跳转内容是视频时,只使用.doc-video展示视频小图标;当内容是音频时,叠加使用.doc-audio展示音频小图标。在IOS上表现正常,在Android上音频小图标只展示了左上角四分之一。
.doc-video { // 视频小图标,
display: inline-block;
vertical-align: middle;
width: 24px;
height: 24px;
background: url(../images/icon-video.png) no-repeat;
background-size: 100% 100%;
}
.doc-audio { // 音频小图标
background: url(../images/icon-audio.png) no-repeat;
}
解决办法:.doc-audio覆盖.doc-video的background样式时,去掉了background-size属性,把这个属性加上Android上也正常了。
.doc-audio {
background: url(../images/icon-audio.png) no-repeat;
background-size: 100% 100%;
}
background-size 属性规定背景图像的尺寸。
20Y-05M:HTML5 <input type="number'/>手机浏览器不支持
在Android/iOS手机上:
<input type="number"/> // 唤起数字键盘,不是纯数字键盘,且设置type=number情况下,一旦输入字母,keydown/keypress/keyup获取的e.target.value变为空
<input type="tel" pattern="[0-9]*"/> // 唤起纯数字键盘,pattern生效,建议使用
20Y-05M1:自定义Vue指令限制HTML5输入框可输入类型
(代码兼容Android和iOS)
(1)<input v-enter-chars:50 type="text" placeholder="请输入真实姓名">
/**
* 只允许输入中英文字符
* @directive: v-enter-chars
*/
export let enterChars = {
bind(el, binding) {
const bindLen = isNaN(binding.arg) ? 500 : Number.parseInt(binding.arg) // 默认限制长度500
const nonChar = /[^\u4e00-\u9fa5a-zA-Z]/ig // 非汉字或英文字符Regex i 大小写不敏感 g 全局匹配
const target = el instanceof HTMLInputElement ? el : el.querySelector("input")
target.addEventListener("keyup", e => {
console.warn('keyup -- e.target.value', e.target.value); // keyup是获取触发事件之后的值
if (/[a-zA-Z]$/.test(e.target.value)) { // 字母按键可能是在输入中文
const strLen = e.target.value.replace(/[^\x00-\xff]/g,"01").length // 计算字符串长度(区分中文和英文)
console.log('strLen', strLen, 'limit', bindLen);
if (strLen > bindLen) {
e.target.value = getSubStr(e.target.value, bindLen)
}
e.target.dispatchEvent(new Event("input"))
} else {
if (nonChar.test(e.target.value)) {
e.target.value = e.target.value.replace(nonChar, "")
}
const strLen = e.target.value.replace(/[^\x00-\xff]/g,"01").length // 计算字符串长度(区分中文和英文)
console.log('strLen', strLen, 'limit', bindLen);
if (strLen > bindLen) {
e.target.value = getSubStr(e.target.value, bindLen)
}
e.target.dispatchEvent(new Event("input"))
}
})
target.addEventListener("paste", e => {
console.warn('paste -- e.target.value', e.target.value);
if (nonChar.test(e.target.value)) {
e.target.value = e.target.value.replace(nonChar, "")
}
const strLen = e.target.value.replace(/[^\x00-\xff]/g,"01").length // 计算字符串长度(区分中文和英文)
console.log('strLen', strLen, 'limit', bindLen);
if (strLen > bindLen) {
e.target.value = getSubStr(e.target.value, bindLen)
}
e.target.dispatchEvent(new Event("input"))
})
}
}
// 从头截取指定长度字符串,区分中英文
function getSubStr(str, limit) {
let count = 0
let result = ''
for (let i = 0; i < str.length; i++) {
let charCode = str.charCodeAt(i)
if (charCode >= 0 && charCode <= 128 && count + 1 <= limit) {
result += str[i]
count++
} else if (count + 2 <= limit) {
result += str[i]
count += 2
} else {
break
}
}
return result
}
(2)<input v-restrict:11="/\D/g" type="tel" pattern="[0-9]*" placeholder="请输入手机号码">
/**
* 限制输入
* 限制内容正则表达式由指令绑定值传入,如: v-restrict:15="/\D/" 限制输入非数字,长度限制15个字符
* @directive: v-restrict
*/
export let restrict = {
bind(el, binding) {
const bindLen = isNaN(binding.arg) ? 500 : Number.parseInt(binding.arg) // 默认限制长度500
const bindReg = binding.value instanceof RegExp ? binding.value : new RegExp("") // 默认不限制输入内容
const target = el instanceof HTMLInputElement ? el : el.querySelector("input")
target.addEventListener("keydown", e => {
console.warn('v-restrict -- keydown -- e.target.value', e.target.value); // keydown, keypress 是获取触发事件之前的值
// 如果HTML5 <input>标签的type=number,则输入字母后,获取的e.target.value变为空
if (bindReg.test(e.target.value)) { // Regex check
e.target.value = e.target.value.replace(bindReg, "")
// e.target.dispatchEvent(new Event("input"))
}
if (e.target.value.length >= bindLen) {
e.target.value = getSubStr(e.target.value, bindLen)
// if (e.preventDefault) {
// e.preventDefault()
// } else {
// e.returnValue = false
// }
}
e.target.dispatchEvent(new Event("input"))
})
target.addEventListener("keyup", e => {
console.warn('v-restrict -- keyup -- e.target.value', e.target.value); // keyup是获取触发事件之后的值
if (bindReg.test(e.target.value)) { // Regex check
e.target.value = e.target.value.replace(bindReg, "")
// e.target.dispatchEvent(new Event("input"))
}
if (e.target.value.length >= bindLen) {
e.target.value = getSubStr(e.target.value, bindLen)
// if (e.preventDefault) {
// e.preventDefault()
// } else {
// e.returnValue = false
// }
}
e.target.dispatchEvent(new Event("input"))
})
target.addEventListener("paste", e => {
console.warn('v-restrict -- paste -- e.target.value', e.target.value); // keyup是获取触发事件之后的值
if (bindReg.test(e.target.value)) { // Regex check
e.target.value = e.target.value.replace(bindReg, "")
}
if (e.target.value.length >= bindLen) {
e.target.value = getSubStr(e.target.value, bindLen)
}
e.target.dispatchEvent(new Event("input"))
})
}
}
// 从左往右截取字符串指定长度,区分中英文
function getSubStr(str, limit) {
let count = 0
let result = ''
for (let i = 0; i < str.length; i++) {
let charCode = str.charCodeAt(i)
if (charCode >= 0 && charCode <= 128 && count + 1 <= limit) {
result += str[i]
count++
} else if (count + 2 <= limit) {
result += str[i]
count += 2
} else {
break
}
}
return result
}
20Y-08M1:new Date(date)在ios下的兼容性问题。
Google浏览器上new Date('2017-03-08 01:01')
能正确显示, 但是在iOS上或者苹果的Safari浏览器上一直显示NaN,发现是iOS的日期格式跟Windows不一样。
let startTime = new Date('2017-03-08 00:00:00'); //ios中starTime为NaN
let startTime2 = new Date('2017-03-08T00:00:00'); //日期和时间中间加个T,兼容ios
或者
let startTime3 = new Date('2017-03-08 00:00:00'.replace(/\-/g, '/')); //把横杠-换成斜杠/,兼容ios
20Y-08M2:微信端从主页面跳转二级页面选择日期并存储在session缓存,history.back或history.go(-1)返回主页面后,没刷新页面,导致主页面时没有重新执行Vue的声明周期函数,未能获取缓存。
[onpageshow 监听页面是否是缓存页面。](https://www.cnblogs.com/leolovexx/p/7026022.html)
[onpageshow 事件在用户浏览网页时触发。](https://www.runoob.com/jsref/event-onpageshow.html)
onpageshow 事件类似于 [onload] 事件,onload 事件在页面第一次加载时触发, onpageshow 事件在每次加载页面时触发,即 onload 事件在页面从浏览器缓存中读取时不触发。
为了查看页面是直接从服务器上载入还是从缓存中读取,你可以使用 PageTransitionEvent 对象的 persisted 属性来判断。 如果页面从浏览器的缓存中读取该属性返回 ture,否则返回 false。
20Y-08M3:在JS代码中使用了数组的方法Array.isArray(ECMAScript 5.1新增),导致兼容测试在华为荣耀畅玩4、OPPO r9m两款机型上不通过,其他机型测试都通过。
通过排除未使用ES6新语法,确定是未加babel-polyfill垫片导致。
解决办法:由于webpack打包多页项目时没有将babel-polyfill放入每个entry的最前面,也没有单独抽出来放到dll中,所以必须在每个页面单独引入。单独引入方法有require('babel-polyfill')或者import,这两种方式都会经过多余打包,所以用原生的标签引入资源。
<script src="{{data.cdn}}static/js/polyfill.min.js"></script>
其他数组方法所属规范:
Array.map-- ECMAScript 1.6
Array.forEach -- ECMAScript 3
Array.keys() -- ECMAScript 6
20Y-08M4:搭建了多页项目框架golf-home,为了使用ES6及更高级语法,使用了(webpack4+babel7+preset-env预设)在打包时转义成ES5。项目没有新建.babelrc或babel.config.js配置文件,使用默认推荐配置。由于忘记显示配置preset-env,导致箭头函数等都没转义,兼容测试不通过。
package.json:
"@babel/core": "^7.9.6",
"@babel/plugin-transform-runtime": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"add-asset-html-webpack-plugin": "^3.1.3",
"babel-loader": "^8.1.0",
webpack.config.js: 未配置babel预设
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory',
include: resolve('src'),
exclude: resolve('src/assets/swiper.min.js'),
},
配置babel预设后,成功转义箭头函数等高级语法,兼容测试通过:
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory',
include: resolve('src'),
exclude: resolve('src/assets/swiper.min.js'),
options: {
presets: ['@babel/preset-env']
}
},
备注:
webpack4以上内置babel-polyfill,设置useBuiltIns才会生效,usage会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加;
此外,babel-preset-env 插件借助了browserslist库提供了对浏览器版本的配置能力,如在.babelrc添加配置:
{
"presets": [
["@babel/env", {
"targets": {
"node": "current",
"chrome": 52,
"browsers": ["last 2 versions", "safari 7"]
}
}]
]
}
也可在package.json中配置browserslist,如下:
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
配置优先级:
targets.browsers > package.json/browserslist
参考一:关于Babel你只需要知道三个插件
参考二:babel-preset-env使用指南
参考三:useBuiltIns
21Y-04M1:Swiper 3.3.1在配置里设置点击事件,触摸滑动时也触发了点击事件。
var swiperInstance = new Swiper(
"#advanceSwiper" + area.areaCode,
{
autoplay: number > 1 ? 5000 : 0,
autoplayDisableOnInteraction: false,
onClick(swiper) {
// 触摸滑动也会触发click事件
// 如果是水平滑动,currentX和startX不会相等
if (swiper.touches.currentX == swiper.touches.startX) {
var dataIndex = $(swiper.clickedSlide).data(
"swiper-slide-index"
);
var item = area.shopWindowList[dataIndex] || {}
var href = $(swiper.clickedSlide).data("href")
_this.goPage(item.actionUrl || href)
}
},
loop: number > 1 ? true : false
}
)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。