【Vue】自定义指令-v-loading指令的封装

打印 上一主题 下一主题

主题 548|帖子 548|积分 1644

场景
实际开发过程中,发送请求需要时间,在请求的数据未返来时,页面会处于空白状态 => 用户体验不好
需求
封装一个 v-loading 指令,实现加载中的效果
分析

  • 本质 loading效果就是一个蒙层,盖在了盒子上
  • 数据请求中,开启loading状态,添加蒙层
  • 数据请求完毕,关闭loading状态,移除蒙层
实现
1.准备一个 loading类,通过伪元素定位,设置宽高,实现蒙层
   利用伪元素添加的好处就是添加和移除会方便一些,如果准备dom元素,则添加和移除需要把这个节点添加和移除。但如果是伪元素,只需要添加和移除类就行了。
  2.开启关闭 loading状态(添加移除蒙层),本质只需要添加移除类即可
3.结合自定义指令的语法进行封装复用
  1. .loading:before {
  2.   content: "";
  3.   position: absolute;
  4.   left: 0;
  5.   top: 0;
  6.   width: 100%;
  7.   height: 100%;
  8.   background: #fff url("./loading.gif") no-repeat center;
  9. }
复制代码
核心思绪:

  • 准备类名 loading,通过伪元素提供遮罩层
  • 添加或移除类名,实现loading蒙层的添加移除
  • 利用指令语法,封装 v-loading 通用指令
    inserted 钩子中,binding.value 判断指令的值,设置默认状态
    update 钩子中,binding.value 判断指令的值,更新类名状态

代码示例
  1. <template>
  2.   <div class="main">
  3.     <div class="box" v-loading="isLoading">
  4.       <ul>
  5.         <li v-for="item in list" :key="item.id" class="news">
  6.           <div class="left">
  7.             <div class="title">{{ item.title }}</div>
  8.             <div class="info">
  9.               <span>{{ item.source }}</span>
  10.               <span>{{ item.time }}</span>
  11.             </div>
  12.           </div>
  13.           <div class="right">
  14.             <img :src="item.img" alt="">
  15.           </div>
  16.         </li>
  17.       </ul>
  18.     </div>
  19.     <!-- 第二个盒子 -->
  20.     <div class="box2" v-loading="isLoading2"></div>
  21.   </div>
  22. </template>
  23. <script>
  24. // 安装axios =>  yarn add axios
  25. import axios from 'axios'
  26. // 接口地址:http://hmajax.itheima.net/api/news
  27. // 请求方式:get
  28. export default {
  29.   data () {
  30.     return {
  31.       list: [],
  32.       isLoading: true,
  33.       isLoading2: true
  34.     }
  35.   },
  36.   async created () {
  37.     // 1. 发送请求获取数据
  38.     const res = await axios.get('http://hmajax.itheima.net/api/news')
  39.    
  40.     setTimeout(() => {
  41.       // 2. 更新到 list 中,用于页面渲染 v-for
  42.       this.list = res.data.data
  43.       this.isLoading = false
  44.     }, 2000)
  45.   },
  46.   directives: {
  47.     loading: {
  48.       inserted (el, binding) {
  49.         // 应该需要根据isLoading的初始值关联起来
  50.         // el.classList.add('loading')
  51.         binding.value ? el.classList.add('loading') : el.classList.remove('loading')
  52.       },
  53.       update (el, binding) {
  54.         binding.value ? el.classList.add('loading') : el.classList.remove('loading')
  55.       }
  56.     }
  57.   }
  58. }
  59. </script>
  60. <style>
  61. .loading:before {
  62.   content: '';
  63.   position: absolute;
  64.   left: 0;
  65.   top: 0;
  66.   width: 100%;
  67.   height: 100%;
  68.   background: #fff url('./loading.gif') no-repeat center;
  69. }
  70. .box2 {
  71.   width: 400px;
  72.   height: 400px;
  73.   border: 2px solid #000;
  74.   position: relative;
  75. }
  76. .box {
  77.   width: 800px;
  78.   min-height: 500px;
  79.   border: 3px solid orange;
  80.   border-radius: 5px;
  81.   position: relative;
  82. }
  83. .news {
  84.   display: flex;
  85.   height: 120px;
  86.   width: 600px;
  87.   margin: 0 auto;
  88.   padding: 20px 0;
  89.   cursor: pointer;
  90. }
  91. .news .left {
  92.   flex: 1;
  93.   display: flex;
  94.   flex-direction: column;
  95.   justify-content: space-between;
  96.   padding-right: 10px;
  97. }
  98. .news .left .title {
  99.   font-size: 20px;
  100. }
  101. .news .left .info {
  102.   color: #999999;
  103. }
  104. .news .left .info span {
  105.   margin-right: 20px;
  106. }
  107. .news .right {
  108.   width: 160px;
  109.   height: 120px;
  110. }
  111. .news .right img {
  112.   width: 100%;
  113.   height: 100%;
  114.   object-fit: cover;
  115. }
  116. </style>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表