当前位置: 首页 > 知识库问答 >
问题:

vue.js - uniapp 开发安卓APP 一般怎么获取DOM节点?

阎唯
2023-08-17

场景:

页面中用到了 uview 的 u--textarea 文本域组件,和常见文本输入框一样,如果被点击的位置已经有内容,则被点击的位置闪烁光标,如果被点击的位置还没有内容,则在内容结尾闪烁光标。同时,在文本域获取焦点后高度变小,给弹出的软键盘腾空位置。如下图:


问题:

如果点击的位置被包含在了文本域输入框变小后的展示区内,没有问题,但是如果点击的位置只被包含在。高度缩小前的展示区域,没有被包含在高度缩小后的展示区域,那么输入框缩小后光标就不会直接展示,需要手动滑动,或者是直接输入/删除字符后文本才会滚动到光标位置。

实际解决的时候遇到下面两个困难:

1 this.$refs
通过this.$refs 虽然可以获取到 u--textarea 组件,但是这个组件本身并没有提供滚动内容区和获取,设置光标位置的方法。

2 document.getElement...
通过浏览器查看发现 u--textarea 组件里封装的就是原生 textarea 并提供了一个类名“uni-textarea-textarea” 但是在 mounted 中 console.log(document) 直接输出 undefined 这里有个疑问,运行到APP 是没有 document 对象吗?为什么会是 undefined ?

3 通过 uniapp 官网找到了 uni.createSelectorQuery(),这个我看提供了几个 api 是可以获取各种信息,但好像就是没有提供 DOM 对象本身啊?!

4 我现在的思路是拿到 u--textarea 内部封装的 textarea 后就可以使用selection-start、selection-end、cursor、几个属性配合着失焦重新获得焦点就可以实现了,但是感觉非常二把刀,有没有更好的解决思路?

组件代码:

<template>    <view class="body" ref='nihaoa'>        <!-- 详情页 -->            <text>姓名</text>            <u--input placeholder="请输入内容" border="surround" v-model="nameInput"/>            <text class="oop" id="oop">电话号码</text>            <u--input placeholder="请输入内容" border="surround" v-model="numberInput"/>            <text>详情</text>            <u-textarea             ref=''            :maxlength="-1"            v-model="msgInput"             placeholder="请输入内容"             :height="infoHeight"             :adjust-position="false"            />                </view></template><script>import {nanoid} from  "nanoid"    const { createClient } = require("webdav/dist/web");    export default {        props:['showRow'],        data() {            return {                // 列表数组本地缓存                "userlist":[],                // 姓名输入框输入的内容                "nameInput":'',                // 电话输入框输入的内容                "numberInput":'',                // 详情文本框输入的内容                "msgInput":'',                // 当前被编辑条目的key                "key":'',                // 数据被修改,是否保存,用于初次加载,避免保存修改使用                "saveFlg":false,                // 键盘高度                "KeyboardHeight":0,            }        },        computed:{            infoHeight(){                if(this.KeyboardHeight){                    return `30vh`                }else{                    return "70vh"                }            }        },    watch:{      nameInput(){        this.chackSave()      },      numberInput(){        this.chackSave()      },      msgInput(){        this.chackSave()      },    },        onLoad(queryy){            this.userlist=this.$store.state.customerList            if(queryy.key=="undefined"){                this.saveFlg=true                return            }            let timeObj=this.userlist.filter(item=>item.key==queryy.key)[0]                this.key=timeObj.key                this.nameInput=timeObj.name                this.numberInput=timeObj.number                this.msgInput=timeObj.msg                this.$nextTick(()=>{                    this.saveFlg=true                })                    },        mounted(){            // console.log(document)            uni.onKeyboardHeightChange(this.keyBarEvent)            },        beforeDestroy(){            uni.offKeyboardHeightChange(this.keyBarEvent)        },        methods: {            // 键盘高度变化方法            keyBarEvent(event){                // uni-textarea-textarea                console.log('键盘高度变了')                this.KeyboardHeight=event.height                setTimeout(()=>{                                        console.log('?????????????????????????????????????')                                        console.log(this.$refs.nihaoa)                                        // const query = uni.createSelectorQuery().in(this);                    // let timeObj=query.select('oop')                    // console.log(timeObj)                                                                                // const query = uni.createSelectorQuery().in(this);                    // let timeObj=query.select('.uni-textarea-textarea')                    // console.log(timeObj.selectionStart)                                                                            },2000)            },            // 检查是否对数据进行保存并持久化            chackSave(){                if(this.saveFlg){                    this.save()                    this.$store.dispatch('writeToFile')                }            },            save(){                // 将当前内容封装为对象                const timeobj={                    "key":this.key,                    "name":this.nameInput,                    "number":this.numberInput,                    "msg":this.msgInput                }                // 标识是否有输入内容                const flg=this.nameInput.trim()!="" || this.numberInput.trim()!="" || this.msgInput.trim()!=""?true:false                // 修改老人数据(有输入内容,且有对应的key)                if(flg && this.key!=''){                    this.userlist=this.userlist.filter(item=>item.key!=this.key)                    this.userlist.unshift(timeobj)                }                // 删除一个人的数据(有对应的key,但是没有输入数据)                else if(!flg && this.key!=''){                    this.userlist=this.userlist.filter((item)=>item.key!=this.key)                }                // 添加一个人的数据(有输入的内容,但没有输入的key)                else if(flg && this.key==''){                    this.key=nanoid()                    timeobj.key=this.key                    this.userlist.unshift(timeobj)                }                this.$store.commit('SET_CUSTOMER_LIST',this.userlist)            },            },    }</script><style scoped>.body{    padding: 20rpx;    height: 100vh;    box-sizing: border-box;    position: relative;    overflow: hidden;}.addButton{    position: absolute;    z-index: 99;    right: 20rpx;    bottom: 25rpx;    border-radius: 50%;}</style>

共有1个答案

姬捷
2023-08-17

手搓一个:

<!-- my-textarea.vue --><template>  <view>    <textarea class="uni-textarea-textarea" ref="textarea" v-model="value" @input="onInput" />  </view></template><script>export default {  props: ['value'],  methods: {    onInput(e) {      this.$emit('input', e.target.value);    },    setCursorPosition(position) {      const textarea = this.$refs.textarea;      if (textarea) {        textarea.selectionStart = position;        textarea.selectionEnd = position;      }    }  }};</script>

父组件里用ref 拿到my-textarea 组件的实例:

<template>  <view class="body">    <!-- 其他代码 -->    <my-textarea ref="myTextarea" v-model="msgInput" :height="infoHeight" :adjust-position="false" />  </view></template><script>import MyTextarea from './my-textarea.vue';export default {  components: {    'my-textarea': MyTextarea  },    methods: {    keyBarEvent(event) {      console.log('键盘高度变了');      this.KeyboardHeight = event.height;      setTimeout(() => {        const query = uni.createSelectorQuery().in(this);        query.select('.uni-textarea-textarea').boundingClientRect();        query.exec((res) => {          const cursorPosition = this.calculateCursorPosition(res[0]);           this.$refs.myTextarea.setCursorPosition(cursorPosition);        });      }, 2000);    },    calculateCursorPosition(rect) {      // 根据文本的位置和尺寸信息计算光标应该在哪个位置      // 看实际需求进行计算      return 0; // 返回值    }  }};</script>
 类似资料: