Vue/React 坑收藏
Vue BUG记录
1、自定义组件的slot绑定点击方法,触发事件混乱
//自定义弹窗子组件
<template>
<div v-if="show" class="alertBox">
<div class="overlay"></div>
<div class="alert">
<div class="title" v-if="title">{{title}}</div>
<slot></slot>
<div class="btns" v-if="!hideCancel || !hideConfirm">
<div class="btn"
v-if="!hideCancel"
@tap="handleCancel()"
>{{cancelText || '取消'}}</div>
<div class="btn btn1"
v-if="!hideConfirm"
@tap="handleConfirm($event)"
>{{confirmText || '确定'}}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "modal-box",
props: {
show: Boolean,
title: String,
hideCancel: Boolean,
hideConfirm: Boolean,
cancelText: String,
confirmText: String,
onCancel: {
type: Function
},
onOk: {
type: Function
}
},
data () {
return {
}
},
computed:{},
methods: {
handleCancel() {
if(this.onCancel){
this.onCancel()
}
},
handleConfirm(e) {
console.log('确认', e, e.target)
if(this.onOk){
this.onOk()
}
},
test(){
console.log('子组件test')
}
},
onLoad(option){
console.log('slotttt', this.$slots)
}
}
</script>
//父级引用
<template>
<modal-box
:show="showBox"
title="苹果手机用户购买置顶"
confirmText="点此发送短信"
:onCancel="handleCancel"
:onOk="handleConfirm"
>
<div class="sendMsg" >
<div @click="ddd()">测试</div>
<div @click="ddd()">测试1</div>
<div @click="ddd()">测试2</div>
</div>
</modal-box>
</template>
<script>
import ModalBox from "c/Modal/index.vue";
export default {
components: {
ModalBox
},
data () {
return {
showBox: true,
}
},
computed:{
},
methods: {
showModal(){
this.showBox= true
},
handleCancel(){
console.log('取消')
// this.showBox= false
},
handleConfirm(){
console.log('确定')
},
ddd(){
console.log('clearddd')
}
},
onLoad(option){
},
onShow () {
},
onHide(){
}
}
</script>
期望点击“测试”按钮,只执行ddd()方法,但是奇葩表现是:点“测试”不仅执行了ddd() 还触发了onCancel;点“测试1”不仅执行了ddd() 还触发了onOk;点“测试2”只执行了ddd() ;
为什么父级slot绑定的方法会触发到自定义组件中的其他方法···
然后我用mpvue2.0版本测试,也是同样的问题
但是我用vue测试,没问题···
mpvue坑还是很多的 导致官方都更不下去了 233333
解决方法: 子组件两个@tap改成@touchstart,也可以用@ touchend,这只能暂时解决绑定事件的问题,组件再复杂点就不行了。
其实这里面还有一个问题 slot内容中如果绑定了父组件的状态,状态改变时,slot是不会跟着渲染的··· 这个问题的处理方法点这里。但是!渲染可以了,动态改变还是不行
参考:slot中组件数据无法渲染 #409、组件嵌套slot问题 #427
最后,我决定不用slot了 辣子鸡里面全是辣鸡
2、mpvue的computed不能正常渲染
正常vue可以通过computed传参的方式 渲染不同内容 如:
<div
class="item"
:class="'item'+index"
v-for="(item, index) in list"
>
{{getTheData(item.val)}}
</div>
computed: {
getTheData() {
return function(name){
console.log(name, this[`${name}`])
return this[`${name}`];
}
}
}
但是在mpvue中执行以上代码,console正常,但是页面渲染没有内容!什么👻!
所以只能迂回了 真滴是操碎了心
<div
class="item"
:class="'item'+index"
v-for="(item, index) in list"
>
{{getTheData[index].name}}
</div>
computed: {
getTheData() {
let _this = this
let result = [];
_this.list.map(res => {
result.push(_this[`${res.val}`])
})
return result;
}
}
辣子鸡里面全是辣鸡
3、封装input用了v-model就不能用动态type
<input :type="type || 'text'" v-model="value" />
上面这样写报错:v-model does not support dynamic input types. Use v-if branches instead.
意思就是用了v-model就不能用动态的type,只能用v-if代替
<input type="number" v-if="type == 'number'" v-model="value" />
<input type="text" v-else v-model="value" />
4、mpvue同一组件再一个页面被多次调用,slot渲染出错
<template>
<modal-box>
<div>111</div>
</modal-box>
<modal-box>
<div>222</div>
</modal-box>
</template>
<script>
import ModalBox from "c/Modal/index.vue";
export default {
components: {
ModalBox,
},
//...
}
</script>
像上面这样同一组件被调用多次,slot内容就不对了,用具名slot分发也不行,只调用1个是正常的。奇葩的是,我重新编译一下显示就没问题了。。。。。。 但是!如果要在slot内容中绑定data,还是不行!也就是只能显示<div>111</div>
这种,不能显示<div>{{val}}</div>
这种。 反正老项目,也不想浪费时间纠结了,第二个就不用组件了。 哎~ react真香!
Taro 问题记录
1、自定义组件createSelectorQuery获取不到元素
const query = this.interface.createSelectorQuery()
query.select('#dom-id').boundingClientRect((res) => {
console.log('info', res) //res为null
}).exec()
const query = this.interface.createSelectorQuery().in(this)
query.select('#dom-id').boundingClientRect((res) => {
console.log('info', res)
}).exec()
/**
没有console,系统报警告:
An SelectorQuery call is ignored because no proper page or component is found. Please considering using `SelectorQuery.in` to specify a proper one.
意思是因为找不到页面或组件,所以请求被忽略了
**/
正确写法:
const query = this.interface.createSelectorQuery().in(this.$scope)
query.select('#dom-id').boundingClientRect((res) => {
console.log('info', res)
}).exec()
React 问题记录
1、reverse后遍历,总会出错
//根据给定的数字判断属于哪个区间
let arr = [
{ name: '学徒', value: 0 },
{ name: '1-3年', value: 1 },
{ name: '3-5年', value: 3 },
{ name: '5-10年', value: 5 },
{ name: '10-15年', value: 10 },
{ name: '15年以上', value: 15 }
]
private findName = e =>{
let result = arr.reverse().find(res => res.value <= e)
return result? result.name : ''
}
2、微信小程序 支付完成后,从系统支付成功页返回,显示feedback组件失效
const res = await this.interface.requestPayment(response.body);
if (res.errMsg !== 'requestPayment:ok') {
return;
}
let that= this
setTimeout(() => {
//安卓,支付页面返回后,第一时间显示会无效。。。。。加个延时就好了。。。。
//可能是需要dom渲染的原因?
that.feedback.showFeedback('giftAlert')
},500)
this.feedback.showToast('充值成功'); //这个是可以正常触发的
3、A页面执行setTimeout,中途切页面后,setTimeout会继续执行,但是里面的this方法无效
private handleShowPullDownNoticebar = () => {
this.setState({
showPulldownNoticebar: true
})
}
private hidePullDownNoticebar = () => {
this.setState({
showPulldownNoticebar: false
})
setTimeout(() => {
console.log("timeout") //可以正常console;
this.handleShowPullDownNoticebar() //跳页后不执行
//feedbackObservable.trigger('showIndexPulldownNotice', 1) //迂回
}, 8000)
}
因为切换页面后,A页面组件已经被销毁,定时器虽然会正常执行,但其中的方法执行的时候已经是不存在了。
解决方法:可以迂回一下,使用发布订阅trigger一下
4、使用antDesign Pro时,自定义了一个组件,使用Link报错
报错:Uncaught Error: Invariant failed: You should not use <Link> outside a <Router>
Link
外面要有BrowserRouter
包裹
import Link from 'umi/link';
import { BrowserRouter, Route } from 'react-router-dom';
<BrowserRouter>
<Link to={'/index/main'}>跳转</Link>
</BrowserRouter>
5、使用input上传文件时,onChange拿不到内容
<input type="file" onChange={this.handleFileChange}/>
private handleFileChange = e => {
console.log(e) //直接这样写,拿到的e没有target等内容
}
private handleFileChange = e => {
e.persist() //要加这个东西
console.log(e) //正常
}
6、react-app iphone打开H5页面空白
问题描述:一个react开发的H5页面,页面加了一些正则匹配,打包后安卓、PC打开都正常。但是iphone上不论微信端还是浏览器,页面打开都是空白,title内容都没有。而且这种情况根本不能用vconsole调试。所以只能用safari内置开发功能连接mac调试,调试发现控制台报错SyntaxError: Invalid regular expression: invalid group specifier name
百度查到:如果正则表达式中包含零宽断言的话 , 在安卓手机上正常 , 但是在ios上会报以下错误;常用零宽断言:?<=、?<!、?!、?=
;
我代码中使用了rep = rep.replace(/(?<!(\.|\w))p ?{/g, '.p {');
这样的写法;NO!!!
要改成rep = rep.replace(new RegExp("(?<!(\.|\w))p ?{","g"), '.p {');
这样才OK!!
7、多维数组循环渲染,onClick拿到的数据错乱
{(parsedData && parsedData.length > 0) && parsedData.map(item => (
<View className={styles.sec} key={item.date}>
<View>{item.date}</View>
<View className={styles.lists}>
{item.list && item.list.map(res => (
<View className={styles.albumItem} key={res.id} onClick={() => {
console.log('???', res.id)
this.navigator.push('albumDetail', {id: res.id})
}}>
{res.id}
</View>
))}
</View>
</View>
))}
//{res.id}渲染显示是正确的,但是onClick中的res.id是错误的!!!
上面这个二位数组渲染,页面打印没问题,但是onClick拿的数据不对。
像是第一层循环,每次都会覆盖之前的onClick绑定。所以改成用bind写法
//改成:
onClick={this.handleItemClick.bind(this, res)}
private handleItemClick = (res) => {
console.log('e', res) //console正确
this.navigator.push('albumDetail', {id: res.id})
}
//这样就可以了
还有一种情况:二维数组循环渲染自定义组件,组件的props值也会被覆盖,例:
{(parsedData && parsedData.length > 0) && parsedData.map(item => (
<View className={styles.sec} key={item.date}>
<View>{item.date}</View>
<View className={styles.lists}>
{item.list && item.list.map(res => (
<JobItem
key={res.id}
data={res}
/>
))}
</View>
</View>
))}
//自定义组件JobItem所渲染的数据都是重复的!!!
//改成这样:JobItem渲染拎出来就行了。。。
{(parsedData && parsedData.length > 0) && parsedData.map(item => (
<View className={styles.sec} key={item.date}>
<View>{item.date}</View>
<View className={styles.lists}>
{item.list && item.list.map(res =>
<View>{this.renderJobItem(res)}</View>
)}
</View>
</View>
))}
/** ------- **/
private renderJobItem = (res) => {
return <JobItem
key={res.id}
data={res}
/>
}
8、externalClasses里只有'css-class'有效
子组件里的externalClasses
别的名字都无效,例如InputTextarea
和FormTextarea
里的第二个'css-placeholder-class'
就不起作用:
interface Props extends Omit<TextareaProps, 'className' | 'placeholderClass'> {
cssClass?: string;
cssPlaceholderClass?: string;
}
export default class FormTextarea extends Taro.Component<Props> {
externalClasses = ['css-class', 'css-placeholder-class'];
/** 省略 **/
className={cx(styles.input, 'css-class')} //有效
className={cx(styles.textarea, 'css-placeholder-class')} //无效
/** 省略 **/
}
原因是/config/index.js
里面有一个配置jsxAttributeNameReplace
:
jsxAttributeNameReplace: {
cssClass: 'css-class',
cssPlaceholderClass: 'css-placeholder-class', //这里加上就行
//额外加的externalClasses 都要在这里先配置,PS:新版本的Taro已移除这个配置。
}
9、无状态函数组件中直接调用get函数无效
private get isVip() {
const { userinfo } = this.state
return !!(userinfo && userinfo.is_vip)
}
private renderFooter = () => {
return (
<View className={styles.btns}>
{this.isVip? (
<View>1</View>
): (
<View>2</View>
)}
</View>
)
} //这样写无效,下面这样写才有效
private renderFooter = () => {
const isvip = this.isVip;
return (
<View className={styles.btns}>
{isvip? (
<View>1</View>
): (
<View>2</View>
)}
</View>
)
}
10、打包报错
TypeError: ctx.modifyWebpackChain is not a function
检查发现是@tarojs/plugin-stylus
跟当前taro/cli
版本不一致,安装对应版本就行了
别的坑记录
1、配置目录别名正确,但编辑器报错
配置目录别名时,tsconfig.json
里正确配置了path
,但编辑器还是显示引用错误。
重启编辑器就好··· PS:我用的VS Code
2、decodeURI无效,但复制测试没问题
从接口获取了一个unicode,需要转换成中文。但是接口获取的unicode字符串代入下面方法后,并不能转换成中文。
这是接口返回数据:{name: "\u4e2d\u56fd", price: 1000, status: 1}
,取其中的name
直接代入decodeURI
转换失败!
但是通过复制接口返回的unicode字符串,然后进行测试,是可以正常转换的。。。目测应该是有转义问题,可这种问题肉眼实在是看不出来啊
private getDecodeUri = (str) => {
console.log('decodeURI:', str, decodeURI(str)) //如果str是接口获取的,控制台打印无效;
console.log('test: ', '\u4e2d\u56fd', decodeURI('\u4e2d\u56fd')) //控制台打印有效
return decodeURI(str)
}
然后网上找到一个偏方,下面这样就可以了!!!???
private getDecodeUri = (str) => {
let test = JSON.stringify(str)
test = test.replace(/\\\\/g, '\\')
return JSON.parse(test)
}
3、State里面的字段要避免特殊名称的命名
taro里的this.setState 遇到一些特殊名称可能会抽风,例如info,data,private等特殊含义的单次都不要用。有的时候还需要setTimeout一下才行