我司用uniapp开发安卓和ios的app要注重用户在app上面使用我司产品体感,从而增加用户的粘度。由于最开始我使用的菊花屏很显然已经不满足需求了,要求换成骨架屏.可是Ui组件库的骨架屏不满足产品的需求。
主要实现思路是通过定位脱离文档直接将对应的内容固定到指定区域.那么如何获取容器的定位值和大小呢?就是利用uniapp提供的这个方法uni.createSelectorQuery()
uni.createSelectorQuery()使用方法和JS中获取QueryselectAll一模一样返回值就是下面这样的
步骤一:首先创建一个Skeleton组件 完整代码直接复制即可 建议在编辑器阅读更佳
<template>
<!-- 骨架屏的高度宽度和背景,用绝对定位提高层级 -->
<view v-if="show">
<view
class="box"
:style="{
width: windowWidth,
height: windowHeight,
backgroundColor: bgColor,
position: 'absolute',
top: top,
left: left,
}"
>
<view
v-for="(item, index) in rectNodes"
:key="index + 'Rect'"
class="skeleton-fade"
:style="{
width: item.width + 'px',
height: item.height + 'px',
backgroundColor: elColor,
position: 'absolute',
top: item.top + 'px',
left: item.left + 'px',
}"
>
</view>
<view
v-for="(item, index) in circleNodes"
:key="index"
class="skeleton-fade"
:style="{
width: item.width + 'px',
height: item.height + 'px',
backgroundColor: elColor,
borderRadius: item.width / 2 + 'px',
position: 'absolute',
top: item.top + 'px',
left: item.left + 'px',
}"
>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted, getCurrentInstance } from "vue";
let systemInfo = uni.getSystemInfoSync();
let windowWidth = ref(systemInfo.windowWidth + "px");
let windowHeight = ref(systemInfo.windowHeight + "px");
let bgColor = ref("#fff");
let elColor = ref("#e5e5e5");
let top = ref(0);
let left = ref(0);
/* 控制骨架屏显示 */
const props = defineProps({
show: {
type: Boolean,
default: true,
},
});
let rectNodes = ref([]);
let circleNodes = ref([]);
/* 获取当前组件的实例 vue2里面是用this vue3里面没有this就要换成getCurrentInstance()来获取实例 */
let Instance = getCurrentInstance();
let getRectEls = () => {
/* 虽然有两个query但是如果只开发H5就可以提出去公用一个 但是如果是APP绝对不能提出去 否则报错 TypeError: Cannot read properties of undefined (reading 'nodeId') */
let query = uni.createSelectorQuery().in(Instance);
/*query.selectAll 参数就是class类名 可以获取到所有带skeleton-rect类名的节点 这个类名可以自己起*/
query
.selectAll(".skeleton-rect")
.boundingClientRect((res) => {
/* 获取到skeleton-rect节点的集合*/
rectNodes.value = res;
})
.exec(function () {});
};
let getCircleEls = () => {
/* 虽然有两个query但是如果只开发H5就可以提出去公用一个 但是如果是APP绝对不能提出去 否则报错 TypeError: Cannot read properties of undefined (reading 'nodeId') */
let query = uni.createSelectorQuery().in(Instance);
/*query.selectAll 参数就是class类名 可以获取到所有带skeleton-circle类名的节点 这个类名可以自己起 */
query
.selectAll(".skeleton-circle")
.boundingClientRect((res) => {
/* 获取到skeleton-circle节点的集合*/
circleNodes.value = res;
})
.exec(function () {});
};
/* setup默认是在DOM挂载前 我们必须等DOM成功挂载后才能获取到节点 选择onMounted调用 */
onMounted(() => {
getCircleEls();
getRectEls();
});
</script>
<style lang="scss" scoped>
/* 这里我是不想让骨架屏滚动 默认就可视区域大小 */
.box {
height: 100vh !important;
overflow: hidden !important;
}
</style>
页面使用:引入即可 show是控制骨架屏状态 一版在后端数据返回完成改成false即可 注意这里不需要使用v-if因为我们是用定位脱离了文档流 使用z-index进行覆盖
template里面使用 在需要的节点上面填写刚才自己起的类名我这里 两个不同的类名代表的一个圆一个是方行 就是这么简单
let show = ref(true)
/* 我这边用的是定时器来模拟后端数据异步返回的结果从而实现骨架屏 */
onMounted(()=>{
setTimeout(()=>{
show.value=false
},3000)
})
效果图
注意:踩坑这个bug是在App上会出现H5不会出现 我还找了很久这个问题点最后就是因为我偷懒简化代码的缘故
由于我看到这两行代码是相同的我就提取成全局的然后就报错,正确的写法就是不能提取成全局每个函数里面单独一个.如果你只开发H5怎样写都无所谓.