定义全局骨架屏组件(vue3)

678 阅读1分钟

1、新建 src/components/Skeleton/index.vue, 书写骨架屏组件

<template>
  <!-- 决定组件的宽高 -->
  <div class="skeleton shan" :style="{ width: width + 'px', height: height + 'px' }">
    <!-- 决定组件的背景色 -->
    <div class="block" :style="{ backgroundColor: bg}"></div>
  </div>
</template>
<script>
export default {
  name: 'Skeleton',
  props: {
    // 宽度定制
    width: {
      type: [Number, String],
      default: 100
    },
    // 高度定制
    height: {
      type: [Number, String],
      default: 60
    },
    // 背景颜色定制
    bg: {
      type: String,
      default: '#ccc'
    }
  }
}
</script>
<style scoped lang="less">
.skeleton {
  display: inline-block;
  position: relative;
  overflow: hidden;
  vertical-align: middle;
  .block {
    width: 100%;
    height: 100%;
    border-radius: 2px;
  }
}
.shan {
  &::after {
    content: "";
    position: absolute;
    animation: shan 1.5s ease 0s infinite;
    top: 0;
    width: 50%;
    height: 100%;
    background: linear-gradient(
      to left,
      rgba(255, 255, 255, 0) 0,
      rgba(255, 255, 255, 0.3) 50%,
      rgba(255, 255, 255, 0) 100%
    );
    transform: skewX(-45deg);
  }
}
@keyframes shan {
  0% {
    left: -100%;
  }
  100% {
    left: 120%;
  }
}
</style>

2、新建 src/components/index.js,以插件形式注册为全局可用

法1:批量

export default { // 默认导出
  install (app) {
    // 1.深度查找每一项
    const requireComponet = require.context('./', true, /\.vue$/)
    // 2.循环遍历深度查找的每一项
    requireComponet.keys().forEach(item => {
      // 3.获取数组对象
      const moduleObj = requireComponet(item).default
      console.log(moduleObj, '00')
      // 4.循环注册组件
      app.component(moduleObj.name, moduleObj)
    })
  }
}

法2:单个

import Skeleton from './Skeleton'
export default {
  install (app) {
    app.component(Skeleton.name, Skeleton)
  }
}

3、main.js 中 导入注册插件

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

// 导入批量或单个注册的全局组件函数
import componentPlugins from './components'

// 链式编程: createApp(App).use(componentPlugins)
createApp(App).use(store).use(router).use(componentPlugins).mount('#app')

4、需要的页面使用

  • 根据需求:传入宽、高或背景颜色即可
<template>
  <div class="home-category">
     <ul class="menu">
         <!-- v-if 和 v-for 不能一起用 所以包个 template -->
         <!-- 1.数组没有长度就显示骨架屏 -->
        <template v-if="!$store.state.category.list.length">
            <li v-for="i in 9" :key="i">
                <RouterLink to="/"><XtxSkeleton :width="66" :height="19"></XtxSkeleton></RouterLink>
                <RouterLink to="/"><XtxSkeleton :width="66" :height="19"></XtxSkeleton></RouterLink>
                <RouterLink to="/"><XtxSkeleton :width="56" :height="19"></XtxSkeleton></RouterLink>
            </li>
        </template>
        <!-- 2.数组有长度就循环渲染 -->
        <template v-else>
             <li v-for="item in $store.state.category.list" :key="item.id">
             <RouterLink to="/">{{item.name}}</RouterLink>
               <template v-if="item.children.length > 0">
                  <RouterLink  to="/" v-for="subItem in item.children.slice(0,2)" :key="subItem.id">{{subItem.name}}</RouterLink>
                  <!-- 弹层 -->
                  <div class="layer">
                     <h4>分类推荐 <small>根据您的购买或浏览记录推荐</small></h4>
                     <ul>
                       <li v-for="goods in item.goods" :key="goods.id">
                         <RouterLink to="/">
                         <img :src="goods.picture" alt="">
                           <div class="info">
                             <p class="name ellipsis-2">{{goods.name}}</p>
                             <p class="desc ellipsis">{{goods.desc}}</p>
                             <p class="price"><i>¥</i>{{goods.price}}</p>
                           </div>
                         </RouterLink>
                       </li>
                     </ul>
                  </div>
               </template>
            </li>
         </template>
      </ul>
   </div>
</template>

<script>
export default {
  name: 'HomeCategory'
}
</script>
<style scoped lang='less'>
.home-category {
  width: 250px;
  height: 500px;
  background: rgba(0, 0, 0, 0.8);
  position: relative;
  z-index: 99;
  .menu {
    li {
      padding-left: 40px;
      height: 55px;
      line-height: 55px;
      &:hover {
        background: #27BA9B;
      }
      a {
        margin-right: 4px;
        color: #fff;
        &:first-child {
          font-size: 16px;
        }
      }
      .layer {
        width: 990px;
        height: 500px;
        background: rgba(255, 255, 255, 1);
        position: absolute;
        left: 250px;
        top: 0;
        display: none;
        padding: 0 15px;
        h4 {
          font-size: 20px;
          font-weight: normal;
          line-height: 80px;
          small {
            font-size: 16px;
            color: #666;
          }
        }
        ul {
          display: flex;
          flex-wrap: wrap;
          li {
            width: 310px;
            height: 120px;
            margin-right: 15px;
            margin-bottom: 15px;
            border: 1px solid #eee;
            border-radius: 4px;
            background: #fff;
            &:nth-child(3n) {
              margin-right: 0;
            }
            a {
              display: flex;
              width: 100%;
              height: 100%;
              align-items: center;
              padding: 10px;
              &:hover {
                background: #e3f9f4;
              }
              img {
                width: 95px;
                height: 95px;
              }
              .info {
                padding-left: 10px;
                line-height: 24px;
                overflow: hidden;
                .name {
                  font-size: 16px;
                  color: #666;
                }
                .desc {
                  color: #999;
                }
                .price {
                  font-size: 22px;
                  color: #CF4444;
                  i {
                    font-size: 16px;
                  }
                }
              }
            }
          }
        }
      }
      &:hover {
        .layer {
          display: block;
        }
      }
    }
  }
}
.ellipsis {
     white-space: nowrap;
     text-overflow: ellipsis;
     overflow: hidden;
   }
.ellipsis-2 {
     word-break: break-all;
     text-overflow: ellipsis;
     display: -webkit-box;
     -webkit-box-orient: vertical;
     -webkit-line-clamp: 2;
     overflow: hidden;
   }
</style>