first
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
## 1.0.1(2023-11-15)
|
||||
1. 修复支付宝小程序报错的BUG
|
||||
## 1.0.0(2023-10-30)
|
||||
1. 新版骨架屏上线
|
||||
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<view class="uv-skeleton">
|
||||
<view v-if="loading">
|
||||
<view v-for="(item, index) in elements" :key="index">
|
||||
<!-- 横向并列布局 -->
|
||||
<view class="uv-skeleton__group" :style="[style(item)]" v-if="item.type=='flex'">
|
||||
<view v-for="(item2,index2) in item.children" :class="[item2.clas]" :style="[style(item2)]" :key="index2">
|
||||
<view v-for="(item3,index3) in item2.elements" :key="index3">
|
||||
<!-- 垂直高度站位 -->
|
||||
<view :style="{height: $uv.addUnit(item3.height,'rpx')}" v-if="item3.type=='gap'"></view>
|
||||
<view :class="[item3.clas, roundClass, animateClass]" :style="[style(item3)]" v-else ref="skeleton"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 自定义骨架屏内容 -->
|
||||
<!-- ps 自定义扩展说明: -->
|
||||
<!-- 如果你需要自定义模板,可以参照这个custom的写法,增加一个skeleton配置类型,编写布局和样式就可以了 -->
|
||||
<!-- 注意事项:为了保证骨架效果和动态效果的一致,扩展时,在你希望实际展示在页面中的元素上加上 :class="[style, animateClass]" 和 :style="[style(item)]" 和 ref="skeleton" -->
|
||||
<view :class="[item.clas, animateClass]" :style="[style(item)]" ref="skeleton" v-else-if="item.type == 'custom'"></view>
|
||||
<!-- 垂直高度站位 -->
|
||||
<view :style="{height: $uv.addUnit(item.height,'rpx')}" v-else-if="item.type=='gap'"></view>
|
||||
<!-- 其他基本单位 line avatar 等 -->
|
||||
<view :class="[item.clas, roundClass, animateClass]" :style="[style(item)]" v-else ref="skeleton"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
|
||||
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
|
||||
// #ifdef APP-NVUE
|
||||
const animation = weex.requireModule('animation');
|
||||
// #endif
|
||||
export default {
|
||||
name: 'uv-skeletons',
|
||||
mixins: [mpMixin, mixin],
|
||||
props: {
|
||||
// 是否显示骨架
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 骨架内容 具体说明参考文档:
|
||||
skeleton: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 是否开启动画效果
|
||||
animate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否圆角骨架风格
|
||||
round: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
...uni.$uv?.props?.skeleton
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
elements: [],
|
||||
opacity: 0.5,
|
||||
duration: 600
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
animateClass() {
|
||||
return this.animate ? 'uv-skeleton--animation' : 'uv-skeleton--static';
|
||||
},
|
||||
roundClass() {
|
||||
return this.round ? 'uv-skeleton--round' : 'uv-skeleton--radius';
|
||||
},
|
||||
style(item) {
|
||||
return item => {
|
||||
const style = {};
|
||||
return this.$uv.deepMerge(style, this.$uv.addStyle(item.style));
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
// #ifdef APP-NVUE
|
||||
if (this.loading && this.animate) {
|
||||
this.$uv.sleep(50).then(res => {
|
||||
this.createAnimation(this.opacity);
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
init() {
|
||||
let elements = [];
|
||||
if (!this.$uv.test.array(this.skeleton)) return this.$uv.error('skeleton参数必须为数组形式,参考文档示例:');
|
||||
this.skeleton.forEach(el => {
|
||||
const elClass = this.getElCounts(el);
|
||||
elements = elements.concat(elClass);
|
||||
})
|
||||
this.elements = [...elements];
|
||||
},
|
||||
/**
|
||||
* 处理骨架屏参数内容
|
||||
* @param {Object} el 每项数据
|
||||
*/
|
||||
getElCounts(el) {
|
||||
let elements = [];
|
||||
let children = [];
|
||||
if (this.$uv.test.number(el)) {
|
||||
elements.push({
|
||||
type: 'gap',
|
||||
height: el
|
||||
});
|
||||
return elements;
|
||||
} else {
|
||||
const type = el.type ? el.type : 'line';
|
||||
const num = el.num ? el.num : 1;
|
||||
const style = el.style ? el.style : {};
|
||||
const styleIsArray = this.$uv.test.array(style);
|
||||
const gap = el.gap ? el.gap : '20rpx';
|
||||
const child = el.children ? el.children : [];
|
||||
for (let i = 0; i < child.length; i++) {
|
||||
children[i] = {
|
||||
clas: child[i].type.indexOf('avatar') > -1 || child[i].type.indexOf('custom') > -1 ? '' : 'uv-skeleton__group__sub',
|
||||
elements: this.getElCounts(child[i])
|
||||
};
|
||||
}
|
||||
for (let i = 0; i < num; i++) {
|
||||
if (gap && i < num && i > 0) {
|
||||
elements.push({
|
||||
type: 'gap',
|
||||
height: gap
|
||||
});
|
||||
}
|
||||
elements.push({
|
||||
clas: `uv-skeleton__${type}`,
|
||||
type,
|
||||
style: styleIsArray ? style[i] : style,
|
||||
gap,
|
||||
children
|
||||
});
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 创建动画
|
||||
*/
|
||||
createAnimation(opacity = 1) {
|
||||
// loading结束之后或未开启动画不执行
|
||||
if (!this.loading || !this.animate) return;
|
||||
let count = 0;
|
||||
const skeletons = this.$refs.skeleton;
|
||||
skeletons.forEach(item => {
|
||||
animation.transition(item, {
|
||||
styles: {
|
||||
opacity: opacity,
|
||||
},
|
||||
duration: this.duration
|
||||
}, () => {
|
||||
count++;
|
||||
if (count >= skeletons.length) {
|
||||
setTimeout(() => {
|
||||
this.createAnimation(opacity < 1 ? 1 : this.opacity);
|
||||
}, 200)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
|
||||
@mixin background {
|
||||
/* #ifdef APP-NVUE */
|
||||
background-color: #e6e6e6;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
|
||||
background-size: 400% 100%;
|
||||
/* #endif */
|
||||
}
|
||||
.uv-skeleton__line {
|
||||
height: 32rpx;
|
||||
// margin-bottom: 30rpx;
|
||||
}
|
||||
.uv-skeleton__line--sm {
|
||||
height: 24rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.uv-skeleton__line--lg {
|
||||
height: 48rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.uv-skeleton--static {
|
||||
@include background;
|
||||
}
|
||||
.uv-skeleton--radius {
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
.uv-skeleton--round {
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
.uv-skeleton__avatar {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50rpx;
|
||||
}
|
||||
.uv-skeleton__avatar--sm {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 25rpx;
|
||||
}
|
||||
.uv-skeleton__avatar--lg {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 100rpx;
|
||||
}
|
||||
.uv-skeleton__group {
|
||||
@include flex;
|
||||
&__sub {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.uv-skeleton--animation {
|
||||
@include background;
|
||||
/* #ifndef APP-NVUE */
|
||||
animation: skeleton 1.8s ease infinite
|
||||
/* #endif */
|
||||
}
|
||||
/* #ifndef APP-NVUE */
|
||||
@keyframes skeleton {
|
||||
0% {
|
||||
background-position: 100% 50%
|
||||
}
|
||||
100% {
|
||||
background-position: 0 50%
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"id": "uv-skeletons",
|
||||
"displayName": "uv-skeletons 骨架屏 全面兼容小程序、nvue、vue2、vue3等多端",
|
||||
"version": "1.0.1",
|
||||
"description": "全新升级骨架屏,更加灵活,体验更加,强烈推荐使用新版骨架屏。一般用于页面在请求远程数据尚未完成时,在内容加载出来前展示与内容布局结构一致的灰白块,提升用户视觉体验。",
|
||||
"keywords": [
|
||||
"uv-skeletons",
|
||||
"uvui",
|
||||
"uv-ui",
|
||||
"skeleton",
|
||||
"骨架屏"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"uv-ui-tools",
|
||||
"uv-text"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Skeletons 新版骨架屏
|
||||
|
||||
> **组件名:uv-skeletons**
|
||||
|
||||
骨架屏一般用于页面在请求远程数据尚未完成时,在内容加载出来前展示与内容布局结构一致的灰白块,提升用户视觉体验。
|
||||
|
||||
新版骨架屏与老版本使用参数有很大的区别,所以才有了新版本,无法替换老版本。
|
||||
|
||||
新版骨架屏比老版本骨架屏更加灵活,理论上简单的左右上下布局结构均可以轻松实现,样式自由度较高,只要你会写css,推荐使用新版。
|
||||
|
||||
# <a href="https://www.uvui.cn/components/skeletons.html" target="_blank">查看文档</a>
|
||||
|
||||
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP)</small>
|
||||
|
||||
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
|
||||
|
||||
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
|
||||
|
||||

|
||||
|
||||
</a>
|
||||
|
||||
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
|
||||
Reference in New Issue
Block a user