1. Demand Analysis
- Add a query request for the layout position of the node. Relative to the display area, in pixels. Its function is similar to DOM's getBoundingClientRect. Return the SelectorQuery corresponding to NodesRef.
- Distinguish between the environment of the applet and H5, and call getBoundingClientRect to obtain the corresponding information.
2. H5 implementation
- Determine whether the incoming element is a window window, and if it is a window window, directly obtain the width and height of the window;
- element, and at the same time, information such as the width and height of the element can be obtained;
- If none are satisfied, return to the default value.
function isWindow(val){
return val === window
}
export const getRect = (elementRef) => {
const element = elementRef
// 判断传入元素是否是window窗口,是window窗口,直接获取窗口的宽高
if (isWindow(element)) {
const width = element.innerWidth
const height = element.innerHeight
return {
top: 0,
left: 0,
right: width,
bottom: height,
width,
height,
}
}
// 是元素,同时可以获取元素的宽高等信息
if (element && element.getBoundingClientRect) {
return element.getBoundingClientRect()
}
// 都不满足,返回默认值
return {
top: 0,
left: 0,
right: 0,
bottom: 0,
width: 0,
height: 0,
}
}
3. Implementation of Taro
- If the element exists, judge to use the corresponding environment to obtain element information;
- The method for obtaining element information of elements used in the H5 environment;
- The WeChat applet environment calls boundingClientRect to obtain element information;
- Return to the default value.
export const getRectByTaro = async (element) => {
// 元素存在,判断使用对应环境获取元素信息
if (element) {
if(process.env.TARO_ENV === "h5"){
// H5环境使用元素的获取元素信息方法
return Promise.resolve(getRect(element))
} else if(process.env.TARO_ENV === "weapp"){
// 微信小程序环境调用 boundingClientRect 获取元素信息
return new Promise((resolve) => {
createSelectorQuery()
.select(`.${element.props.class.split(' ').filter(item => item).join('.')}`)
.boundingClientRect(resolve).exec()
})
}
}
// 返回默认值
return Promise.resolve({
top: 0,
left: 0,
right: 0,
bottom: 0,
width: 0,
height: 0,
})
}
4. Use cases
1. Import
import React, { Component } from 'react';
import { getRectByTaro } from '@utils/use-client-rect';
2. Obtain the getBoundingClientRect information of dom
class page extends Component {
constructor(props) {
this.navbarRef = React.createRef()
}
componentDidShow(){
// 如果元素内有动态信息,需要将获取信息的方法放到请求数据完成,设置数据后边
this.getElementInfo()
}
getElementInfo(){
let _this = this;
let timer = setTimeout(async () => {
clearTimeout(timer)
console.log('_this.navbarRef',_this.navbarRef.current)
let info = await getRectByTaro(_this.navbarRef.current)
console.log('navbarRef', info)
},0)
}
render() {
return (<View className='rui-navbar-current-content' ref={this.navbarRef}></View>)
}
}
5. WeChat applet return sample
6. H5 return sample
7. Complete code
import { createSelectorQuery } from '@tarojs/taro';
function isWindow(val){
return val === window
}
export const getRect = (elementRef) => {
const element = elementRef
// 判断传入元素是否是window窗口,是window窗口,直接获取窗口的宽高
if (isWindow(element)) {
const width = element.innerWidth
const height = element.innerHeight
return {
top: 0,
left: 0,
right: width,
bottom: height,
width,
height,
}
}
// 是元素,同时可以获取元素的宽高等信息
if (element && element.getBoundingClientRect) {
return element.getBoundingClientRect()
}
// 都不满足,返回默认值
return {
top: 0,
left: 0,
right: 0,
bottom: 0,
width: 0,
height: 0,
}
}
export const getRectByTaro = async (element) => {
// 元素存在,判断使用对应环境获取元素信息
if (element) {
if(process.env.TARO_ENV === "h5"){
// H5环境使用元素的获取元素信息方法
return Promise.resolve(getRect(element))
} else if(process.env.TARO_ENV === "weapp"){
// 微信小程序环境调用 boundingClientRect 获取元素信息
return new Promise((resolve) => {
createSelectorQuery()
.select(`.${element.props.class.split(' ').filter(item => item).join('.')}`)
.boundingClientRect(resolve).exec()
})
}
}
// 返回默认值
return Promise.resolve({
top: 0,
left: 0,
right: 0,
bottom: 0,
width: 0,
height: 0,
})
}