Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

给表格添加 loading 蒙层,解决表格 action 和 排序 并行操作导致的数据稳定问题 #328

Open
ly525 opened this issue Aug 29, 2019 · 0 comments

Comments

@ly525
Copy link
Owner

ly525 commented Aug 29, 2019

背景

标签:用户体验
介绍:vuetify 的表格里面,有一列 action,是 switch 切换(开关),点击切换的时候,会发起后端请求。与此同时,vuetify 的表格允许用户排序。

问题

我们发现运营在切换开关的时候(假设运营想 关闭 某个功能,前端发送打开或关闭的请求),在后端请求还没有返回,pending 的时候,运营同学可能会点击表头排序,发起了更新表格排序的请求(数据量较大,后端排序)。此时,切换开关的操作并未完成,数据库中的数据仍然是打开状态,前端在拿到排序后的数据的时候,更新表格(此时之前的开关操作有可能仍未完成)。这样就会把之前运营的关闭操作reset 了。运营此时就有点茫然了:我到底关闭成功了没?不知道

目前的解决方案:

运营在切换开关的时候,显示蒙层(loading 效果),蒙层要能保证运营能看到表格中的数据,只是此时不允许运营在对表格再做其他操作而已,但仍然能够正常查看数据。

演示效果

mbOOeS.gif

代码

vuetify: 2.x
element-ui: 2.11.1
vue cli3.x

稍微晚点补充一个 codepen 的 demo
下面的 demo 部分源码来自 Paginate and sort server-side

// src/mixins/mask-loading.js
import { Loading } from 'element-ui'
const defaultLoadingOptions = {
  background: 'rgba(255, 255, 255, 0.5)'
}

export default {
  data() {
    return {
      loadingInstance: null
    }
  },
  methods: {
    startMaskLoading(target, { background } = defaultLoadingOptions) {
      const loadingInstance = this.$refs.table && Loading.service({
        ...defaultLoadingOptions,
        target: target || this.$refs.table.$el,
        background
      })
      this.loadingInstance = loadingInstance
    },
    stopMaskLoading() {
      this.loadingInstance.close()
    }
  }
}
// xxx.table.vue
// 在有表格需要loading的地方,引入这个mixin
<template>
  <div>
    <v-data-table
      ref="table"
      :headers="headers"
      :items="desserts"
      :options.sync="options"
      :server-items-length="totalDesserts"
      :loading="loading"
      class="elevation-1"
    />
  </div>
</template>

<script>
import maskLoadingMixin from '@/mixins/mask-loading'

export default {
    mixins: [maskLoadingMixin],
    data () {
      return {
        totalDesserts: 0,
        desserts: [],
        loading: true,
        options: {},
        headers: [
          {
            text: 'Dessert (100g serving)',
            align: 'left',
            sortable: false,
            value: 'name',
          },
          { text: 'Calories', value: 'calories' },
          { text: 'Fat (g)', value: 'fat' },
          { text: 'Carbs (g)', value: 'carbs' },
          { text: 'Protein (g)', value: 'protein' },
          { text: 'Iron (%)', value: 'iron' },
        ],
      }
    },
    watch: {
      options: {
        handler () {
          // 在这里 start loading 
          this.startMaskLoading()
          this.getDataFromApi()
            .then(data => {
              this.desserts = data.items
              this.totalDesserts = data.total
              // 在这里停止 loading
              this.stopMaskLoading()
            })
        },
        deep: true,
      },
    },
    mounted () {
      this.getDataFromApi()
        .then(data => {
          this.desserts = data.items
          this.totalDesserts = data.total
        })
    },
    methods: {
      getDataFromApi () {
        this.loading = true
        return new Promise((resolve, reject) => {
          const { sortBy, descending, page, itemsPerPage } = this.options

          let items = this.getDesserts()
          const total = items.length

          if (this.options.sortBy) {
            items = items.sort((a, b) => {
              const sortA = a[sortBy]
              const sortB = b[sortBy]

              if (descending) {
                if (sortA < sortB) return 1
                if (sortA > sortB) return -1
                return 0
              } else {
                if (sortA < sortB) return -1
                if (sortA > sortB) return 1
                return 0
              }
            })
          }

          if (itemsPerPage > 0) {
            items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
          }

          setTimeout(() => {
            this.loading = false
            resolve({
              items,
              total,
            })
          }, 1000)
        })
      },
      getDesserts () {
        return [
          {
            name: 'Frozen Yogurt',
            calories: 159,
            fat: 6.0,
            carbs: 24,
            protein: 4.0,
            iron: '1%',
          },
          {
            name: 'Ice cream sandwich',
            calories: 237,
            fat: 9.0,
            carbs: 37,
            protein: 4.3,
            iron: '1%',
          },
          {
            name: 'Eclair',
            calories: 262,
            fat: 16.0,
            carbs: 23,
            protein: 6.0,
            iron: '7%',
          },
          {
            name: 'Cupcake',
            calories: 305,
            fat: 3.7,
            carbs: 67,
            protein: 4.3,
            iron: '8%',
          },
          {
            name: 'Gingerbread',
            calories: 356,
            fat: 16.0,
            carbs: 49,
            protein: 3.9,
            iron: '16%',
          },
          {
            name: 'Jelly bean',
            calories: 375,
            fat: 0.0,
            carbs: 94,
            protein: 0.0,
            iron: '0%',
          },
          {
            name: 'Lollipop',
            calories: 392,
            fat: 0.2,
            carbs: 98,
            protein: 0,
            iron: '2%',
          },
          {
            name: 'Honeycomb',
            calories: 408,
            fat: 3.2,
            carbs: 87,
            protein: 6.5,
            iron: '45%',
          },
          {
            name: 'Donut',
            calories: 452,
            fat: 25.0,
            carbs: 51,
            protein: 4.9,
            iron: '22%',
          },
          {
            name: 'KitKat',
            calories: 518,
            fat: 26.0,
            carbs: 65,
            protein: 7,
            iron: '6%',
          },
        ]
      },
    },
  }
</script>
@ly525 ly525 changed the title vuetify 结合 element-ui loading 给表格添加 loading 蒙层,解决表格 action 和 排序 并行操作导致的数据稳定问题 Aug 29, 2019
@ly525 ly525 self-assigned this Sep 23, 2019
@ly525 ly525 moved this from B端-工程实践 to B端-设计规范 in 1.3. 效率工程<B端管理后台、表单生成器> Jan 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

1 participant