Vue 在使用v-if的前提下,使用ResizeObserver配合ref获取元素块的高度

72 阅读1分钟

1. Vue 在使用v-if的前提下,使用ResizeObserver配合ref获取元素块的高度

遇到的问题

1. 在computed中没法操作dom元素,比如

computed: {    w() {        return  this.$refs.box.offsetWidth    }}

运行中报undefined错误,后来改成在mounted中获取this.$refs.box.offsetWidth,后来发现,在computed中,DOM元素未加载下来,保险起见,还是在mounted操作DOM

最终方案

在watch里面监听容器显示变化,在v-if 的值为 true的时候,调用监听方法

  watch: {    // Init 控制容器的显示与隐藏    Init(val) {      if (val) {        this.$nextTick(() => {          this.handleWatchElement();        });      }    },  },

关键监听 ResizeObserver()

    handleWatchElement() {      const divElem = this.$refs.myDiv; //  监听元素      if (divElem) {        const resizeObserver = new ResizeObserver(() => {          if (divElem.scrollHeight > divElem.clientHeight && !this.IsScroll) {            this.IsScroll = true; // 该元素有滚动条          } else if (divElem.scrollHeight <= divElem.clientHeight) {            this.IsScroll = false;          }        });        resizeObserver.observe(divElem);      }    },

Easy Mock (presstime.cn)

模拟后端数据

Vue.observable API的使用

这个可以理解成为简化版的Vuex, 因为Vuex使用比较复杂, 在非大型项目中使用起来不方便, 为了简化传值操作, 2.6之后新增此API

使用方法

  1. 像 Vuex 一样, 需要新建一个store.js 文件管理state数据和mutation操作,

  2. 若组件需要使用数据和方法,import 导入store.js 中的 数据和方法即可

  3. 值得注意的是, 数据还是需要放入computed 中, 方法还是需要放入 methods

实例

import Vue from 'vue';​// 微型vuex , 创建一个stateexport const store = Vue.observable({ count: 0, name: 'zs' });​// 创建修改state的方法export const change = {  setCount(count) {    console.log(this);    // 注意这个方法一定不能使用this, 因为调用时this会指向调用这个方法的组件    store.count = count;   },  setName(name) {    store.name = name;  },};

组件内使用

<template>  <div>    <p>count : {{ count }}</p>    <p>name: {{ name }}</p>    <button @click="setCount(count + 1)">+</button>    <button @click="setCount(count - 1)">-</button>    <button @click="setName(newName)">change name</button>  </div></template><script>import { store, change } from '../store/ob';​export default {  data() {    return {      newName: 'NEW NAME',    };  },​  computed: {    count() {      return store.count;    },    name() {      return store.name;    },  },​  methods: {    setCount: change.setCount,    setName: change.setName  },};</script>

优雅更新 props

更新 prop 在业务中是很常见的需求,但在子组件中不允许直接修改 prop,因为这种做法不符合单向数据流的原则,在开发模式下还会报出警告。因此大多数人会通过 $emit 触发自定义事件,在父组件中接收该事件的传值来更新 prop

child.vue:

export defalut {    props: {        title: String      },    methods: {        changeTitle(){            this.$emit('change-title', 'hello')        }    }}

parent.vue: 通过自定义事件来对props进行修改

<child :title="title" @change-title="changeTitle"></child>

export default {    data(){        return {            title: 'title'        }      },    methods: {        changeTitle(title){            this.title = title        }    }}

这种做法没有问题,我也常用这种手段来更新 prop。但如果你只是想单纯的更新 prop,没有其他的操作。那么 sync 修饰符能够让这一切都变得特别简单。

parent.vue:

<child :title.sync="title"></child>

child.vue:

export defalut {    props: {        title: String      },    methods: {        changeTitle(){            this.$emit('update:title', 'hello')        }    }}

只需要在绑定属性上添加 .sync,在子组件内部就可以触发 update:属性名 来更新 prop。可以看到这种手段确实简洁且优雅,这让父组件的代码中减少一个“没必要的函数”。