uniapp 开发安卓APP 一般怎么获取DOM节点?
场景:
页面中用到了 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>
手搓一个:
<!-- 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>
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容