123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- <template>
- <view
- v-if="show"
- class="tn-skeleton-class tn-skeleton"
- :class="[backgroundColorClass]"
- :style="[skeletonStyle]"
- @touchmove.stop.prevent
- >
- <view
- v-for="(item, index) in rectNodes"
- :key="$t.uuid()"
- class="tn-skeleton__item tn-skeleton__item--rect"
- :class="[elBackgroundColorClass, {'tn-skeleton__item--fade': animation}]"
- :style="[itemStyle('rect', item)]"
- ></view>
- <view
- v-for="(item, index) in circleNodes"
- :key="$t.uuid()"
- class="tn-skeleton__item tn-skeleton__item--circle"
- :class="[elBackgroundColorClass, {'tn-skeleton__item--fade': animation}]"
- :style="[itemStyle('circle', item)]"
- ></view>
- <view
- v-for="(item, index) in filletNodes"
- :key="$t.uuid()"
- class="tn-skeleton__item tn-skeleton__item--fillet"
- :class="[elBackgroundColorClass, {'tn-skeleton__item--fade': animation}]"
- :style="[itemStyle('fillet', item)]"
- ></view>
- </view>
- </template>
- <script>
- import componentsColorMixin from '../../libs/mixin/components_color.js'
- export default {
- name: 'tn-skeleton',
- mixins: [ componentsColorMixin ],
- props: {
- // 显示骨架屏
- show: {
- type: Boolean,
- default: false
- },
- // 需要渲染的元素背景颜色
- elBackgroundColor: {
- type: String,
- default: ''
- },
- // 开启加载动画
- animation: {
- type: Boolean,
- default: true
- },
- // 矩形元素自定义样式
- rectCustomStyle: {
- type: Object,
- default() {
- return {}
- }
- },
- // 圆形元素自定义样式
- circleCustomStyle: {
- type: Object,
- default() {
- return {}
- }
- },
- // 圆角元素自定义样式
- filletCustomStyle: {
- type: Object,
- default() {
- return {}
- }
- }
- },
- computed: {
- elBackgroundColorStyle() {
- return this.$t.color.getBackgroundColorStyle(this.elBackgroundColor)
- },
- elBackgroundColorClass() {
- return this.$t.color.getBackgroundColorInternalClass(this.elBackgroundColor)
- },
- // 骨架屏样式
- skeletonStyle() {
- let style = {}
- style.width = this.skeletonWidth + 'px'
- style.height = this.skeletonHeight + 'px'
- if (this.backgroundColorStyle) {
- style.backgroundColor = this.backgroundColorStyle
- }
- style.left = this.left + 'px'
- style.top = this.top + 'px'
- return style
- },
- // 元素样式
- itemStyle() {
- return (type, item) => {
- let style = {}
- style.width = item.width + 'px'
- style.height = item.height + 'px'
- if (this.elBackgroundColorStyle) {
- style.backgroundColor = this.elBackgroundColorStyle
- }
- style.left = (item.left - this.left) + 'px'
- style.top = (item.top - this.top) + 'px'
- if (type === 'rect') {
- Object.assign(style, this.rectCustomStyle)
- } else if (type === 'circle') {
- style.borderRadius = (item.width / 2) + 'px'
- Object.assign(style, this.circleCustomStyle)
- } else if (type === 'fillet') {
- Object.assign(style, this.filletCustomStyle)
- }
- return style
- }
- }
- },
- data() {
- return {
- // 骨架屏宽度
- skeletonWidth: 750,
- // 骨架屏高度
- skeletonHeight: 1500,
- // 圆角元素
- filletNodes: [],
- // 圆形元素
- circleNodes: [],
- // 矩形元素
- rectNodes: [],
- // 元素偏移位置
- top: 0,
- left: 0
- }
- },
- mounted() {
- this.$nextTick(() => {
- // 获取系统信息
- const systemInfo = uni.getSystemInfoSync()
- this.skeletonWidth = systemInfo.safeArea.width
- this.skeletonHeight = systemInfo.safeArea.height
- this.selectQueryInfo()
- })
- },
- methods: {
- // 查询节点信息
- selectQueryInfo() {
- // 获取整个父容器的宽高作为骨架屏的宽高
- // 在微信小程序中,如果把骨架屏放入组件使用,需要in(this)上下文为父组件才有效
- let query = null
- // 在微信小程序中,如果把骨架屏放入组件使用,需要in(this)上下文为父组件才有效
- // #ifdef MP-WEIXIN
- query = uni.createSelectorQuery().in(this.$parent)
- // #endif
- // #ifndef MP-WEIXIN
- query = uni.createSelectorQuery()
- // #endif
- query.selectAll('.tn-skeleton').boundingClientRect().exec((res) => {
- console.log(res);
- this.skeletonWidth = res[0][0].width
- this.skeletonHeight = res[0][0].height
- this.top = res[0][0].bottom - res[0][0].height
- this.left = res[0][0].left
- })
-
- // 获取元素列表
- this.getRectElements()
- this.getCircleElements()
- this.getFillteElements()
- },
- // 矩形元素列表
- getRectElements() {
- let query = null
- // 在微信小程序中,如果把骨架屏放入组件使用,需要in(this)上下文为父组件才有效
- // #ifdef MP-WEIXIN
- query = uni.createSelectorQuery().in(this.$parent)
- // #endif
- // #ifndef MP-WEIXIN
- query = uni.createSelectorQuery()
- // #endif
- query.selectAll('.tn-skeleton-rect').boundingClientRect().exec((res) => {
- this.rectNodes = res[0]
- })
- },
- // 圆形元素列表
- getCircleElements() {
- let query = null
- // 在微信小程序中,如果把骨架屏放入组件使用,需要in(this)上下文为父组件才有效
- // #ifdef MP-WEIXIN
- query = uni.createSelectorQuery().in(this.$parent)
- // #endif
- // #ifndef MP-WEIXIN
- query = uni.createSelectorQuery()
- // #endif
- query.selectAll('.tn-skeleton-circle').boundingClientRect().exec((res) => {
- this.circleNodes = res[0]
- })
- },
- // 圆角元素列表
- getFillteElements() {
- let query = null
- // 在微信小程序中,如果把骨架屏放入组件使用,需要in(this)上下文为父组件才有效
- // #ifdef MP-WEIXIN
- query = uni.createSelectorQuery().in(this.$parent)
- // #endif
- // #ifndef MP-WEIXIN
- query = uni.createSelectorQuery()
- // #endif
- query.selectAll('.tn-skeleton-fillet').boundingClientRect().exec((res) => {
- this.filletNodes = res[0]
- })
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .tn-skeleton {
- position: absolute;
- z-index: 9998;
- overflow: hidden;
- background-color: #FFFFFF;
-
- &__item {
- position: absolute;
- background-color: #F0F0F0;
-
- &--fillet {
- border-radius: 10rpx;
- }
-
- &--fade {
- width: 100%;
- height: 100%;
- background-color: #E6E6E6;
- animation-duration: 1.5s;
- animation-name: blink;
- animation-timing-function: ease-in-out;
- animation-iteration-count: infinite;
- }
- }
- }
-
- @keyframes blink {
- 0% {
- opacity: 1;
- }
- 50% {
- opacity: 0.4;
- }
- 100% {
- opacity: 1;
- }
- }
- </style>
|