美文网首页
Vue/React 坑收藏

Vue/React 坑收藏

作者: G_console | 来源:发表于2020-09-27 14:43 被阅读0次

    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别的名字都无效,例如InputTextareaFormTextarea里的第二个'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一下才行

    Taro3体验记录

    1、每个页面必须要import React from 'react'

    2、子组件不会触发onReady, onShow, onHide

    相关文章

      网友评论

          本文标题:Vue/React 坑收藏

          本文链接:https://www.haomeiwen.com/subject/jxlgxktx.html