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
使用方法
-
像 Vuex 一样, 需要新建一个
store.js文件管理state数据和mutation操作, -
若组件需要使用数据和方法,
import导入store.js中的 数据和方法即可 -
值得注意的是, 数据还是需要放入
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。可以看到这种手段确实简洁且优雅,这让父组件的代码中减少一个“没必要的函数”。