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

作者站长头像
站长
· 阅读数 6

场景:

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

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

问题:

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

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

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个回答
avatar
test
2024-06-28

手搓一个:

<!-- 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>
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容