Vue中nextTick()解析

人走茶凉 提交于 2020-04-24 23:38:31

最近,在开发的时候遇到一个问题,让我对vue中nextTick()的用法加深了了解~

下面是在组件中引用的一个拖拽的组件:

<vue-draggable-resizable
     class="drag-img"
     :w="coordinate[0].width"
     :h="coordinate[0].height"
     :x="coordinate[0].abs"
     :y="coordinate[0].ord"
     @dragging="onDragAvator"
     @resizing="onResizeAvator"
     @dragstop="onDragstopAvator"
     @onDragStart="onDragStartAvator"
     :min-width="50"
     :min-height="50"
     :handles="['tl','tr','br','bl']"
     :lock-aspect-ratio="true"
     :parent="true">
     <img @click="setAvatorDafault" src="@/assets/img/icon_touxiang@2x.png" alt="">          
</vue-draggable-resizable>

这个拖拽组件的横坐标和纵坐标、宽高是由data的一个数据控制的:

data() {
   return {
      coordinate:[{
        width: 50,
        height: 50,
        abs: 10,
        ord: 10
      }]  
    }      
}

在dragging和resizing的过程中,这个数据和dom的操作应该都是双向绑定的:

onResizeAvator: function (x, y, width, height) {
    this.coordinate[0].abs = x
    this.coordinate[0].ord = y
},
onDragAvator: function (x, y) {
    this.coordinate[0].abs = x
    this.coordinate[0].ord = y
},

但是,在编辑回显的时候,需要将异步获取的数据赋给coordinate,再显示到页面。

现在问题来了,当数据coordinate被赋值成异步获取的数据后,页面中的拖拽组件的宽高并没有变化,这是为什么?

methods: {
  getDefaultData() {
      let that = this
      axios.get(this.$store.state.marketinghost
      + '/fission/task/get/bycode?onlischoolCode=' + this.onlischoolCode
      + '&taskCode=' + this.$route.query.id)
      .then(res => {
        if(res.data.code == "1") {
          var data = res.data.data
          if (data.components.length) {
            that.coordinate = data.components
          }
        }
      })
      .catch((err) => {
        Promise.resolve(err);
      })
  }
}
mounted() {
  this.getDefaultData()
}

 加了一个变量控制拖拽组件后,组件DOM会强制性更新,宽高就变成回显时候的值了

<vue-draggable-resizable
     class="drag-img"
     v-if="!editLoading"
     :w="coordinate[0].width"
     :h="coordinate[0].height" :x="coordinate[0].abs" :y="coordinate[0].ord" @dragging="onDragAvator" @resizing="onResizeAvator" @dragstop="onDragstopAvator" @onDragStart="onDragStartAvator" :min-width="50" :min-height="50" :handles="['tl','tr','br','bl']" :lock-aspect-ratio="true" :parent="true"> <img @click="setAvatorDafault" src="@/assets/img/icon_touxiang@2x.png" alt=""> </vue-draggable-resizable>
data() {
   return {
    editLoading: false, coordinate:[{ width: 50, height: 50, abs: 10, ord: 10 }] } }
methods: {
  getDefaultData() { let that
= this that.editLoading = true axios.get(this.$store.state.marketinghost + '/fission/task/get/bycode?onlischoolCode=' + this.onlischoolCode + '&taskCode=' + this.$route.query.id) .then(res => { if(res.data.code == "1") { var data = res.data.data if (data.components.length) { that.coordinate = data.components that.$nextTick(() => { that.editLoading = false }) } } }) .catch((err) => { Promise.resolve(err); })   }
}
mounted() {
  this.
getDefaultData()
}

 为了更加了解nextTick(),下面是vue官网关于异步更新队列的解释:

https://cn.vuejs.org/v2/guide/reactivity.html#%E5%BC%82%E6%AD%A5%E6%9B%B4%E6%96%B0%E9%98%9F%E5%88%97

总之,当你设置 vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新,为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback) :

Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
    return {
      message: '未更新'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = '已更新'
      console.log(this.$el.textContent) // => '未更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '已更新'
      })
    }
  }
})

 因为nextTick()返回的事一个Promise对象,所以也可以写成async/await的方式:

methods: {
  updateMessage: async function () {
    this.message = '已更新'
    console.log(this.$el.textContent) // => '未更新'
    await this.$nextTick()
    console.log(this.$el.textContent) // => '已更新'
  }
}

 

  

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!