繁体   English   中英

(Vue3) 使用 v-model 和 v-on 同步 DOM 元素高度变化的问题

[英](Vue3) Problems syncing DOM element heights change using v-model and v-on

我正在创建一个网站,其中使用v-model将范围 slider 的值绑定到名为rangeValue的属性。 该代码类似于以下内容:

    <template>
       ...
      <input
        type="range"
        min="10"
        max="50"
        class="slider"
        v-model="rangeValue"
        @change="updateHeight()"
      />
      <div class="otherDiv" :style="{ height: `${wrapperHeight}px`></>
      <div
        class="firstDiv"
        ref="first"
        :style="{ width: `${rangeValue}rem` }">
           <!-- There are elements inside whose height is also bound by rangeValue, and some that are toggled on/off via other checkbox inputs, thereby changing the height of firstDiv -->
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          wrapperHeight: 0,
          rangeValue: "10",
      },
      mounted(){
          this.wrapperHeight = this.$refs.first.offsetHeight;
      },
      methods: {
        updateHeight() {
          this.wrapperHeight = this.$refs.first.offsetHeight;
        }
      }
    }
    </script>
    <style>
      ...
    </style>

我想让 otherDiv 的高度与otherDiv的高度相匹配,其高度根据范围firstDiv的变化而变化。 我的问题是firstDiv的高度与范围 slider 的变化同时更新,而otherDiv的高度总是滞后一个“滴答”,更新到firstDiv的值在它被范围 slider 改变之前,而不是之后。 我尝试了各种使用nextTick的实现都无济于事。

简而言之,我需要:

  1. 更新范围 slider
  2. 调整firstDiv的大小,获取它在 DOM 中的高度,调整otherDiv的大小
  3. 重新绘制 DOM(因此两者同时调整大小)。

我希望这是有道理的。 欢迎任何指点,谢谢!

这是你想要达到的目标吗?

 const { createApp, toRefs, reactive, computed } = Vue createApp({ setup: () => toRefs( reactive({ h8: 135 }) ) }).mount("#app")
 #app.grid { display: grid; grid-gap: 0.75rem; grid-template-columns: repeat(2, 1fr); padding: 0.5rem; } #app.grid > * { overflow-y: auto; padding: 0.5rem; border-radius: 5px; box-shadow: inset 0 1px 8px 0 rgb(0 0 0/10%), inset 0 3px 4px 0 rgb(0 0 0 / 7%), inset 0 3px 3px -2px rgb(0 0 0 / 6%); background-color: #f8f8f8; } #app [type="range"] { max-width: 400px; width: 100%; margin: 0 auto; display: block; }
 <script src="https://unpkg.com/vue@3.2.45/dist/vue.global.prod.js"></script> <div id="app"> <input type="range" min="60" max="400" v-model="h8" /> <div class="grid":style="{ height: `${h8}px` }"> <div class="firstDiv">first div</div> <div class="secondDiv"> second div <p v-for="n in 10":key="n">Lorem ipsum dolor sit amet.</p> </div> </div> </div>


您不仅限于拥有共同的父母(这似乎更适合您的情况)。

您可以同步完全不相关的组件,即使在单独的应用程序中也是如此(参见下面的示例)。 您所需要的只是一个单一的事实来源。 我使用了反应式 object 但更常见和有用的实现是使用实际商店(pinia,vuex):

 const { createApp, toRefs, reactive, computed } = Vue const store = reactive({ h8: 85 }); ['input-app', 'app-1', 'app-2'].forEach(app => createApp({ setup: () => toRefs(store) }).mount(`#${app}`))
 #app-1, #app-2 { padding: 0.5rem; }.grid { display: grid; grid-template-areas: "input input" "app-1 app-2"; grid-template-rows: auto 1fr; grid-template-columns: 1fr 1fr; min-height: 100vh; } body { margin: 0 } #input-app { grid-area: input; } #app-1 { grid-area: app-1; } #app-2 { grid-area: app-2; align-self: end; }.firstDiv, .secondDiv { overflow-y: auto; padding: 0.5rem; border-radius: 5px; box-shadow: inset 0 1px 8px 0 rgb(0 0 0/10%), inset 0 3px 4px 0 rgb(0 0 0 / 7%), inset 0 3px 3px -2px rgb(0 0 0 / 6%); background-color: #f8f8f8; } [type="range"] { max-width: 400px; width: 100%; margin: 0 auto 1rem; display: block; }
 <script src="https://unpkg.com/vue@3.2.45/dist/vue.global.prod.js"></script> <div class="grid"> <div id="input-app"> <input type="range" min="60" max="500" v-model="h8" /> </div> <div id="app-1"> <div class="firstDiv":style="{ height: `${h8}px` }"> first div </div> </div> <div id="app-2"> <div class="secondDiv":style="{ height: `${h8}px` }"> second div <p v-for="n in 10":key="n">Lorem ipsum dolor sit amet.</p> </div> </div> </div>

我真的不明白你的目标和高度/宽度关系。

但这里有一个类似的工作操场。

 const { createApp, ref, onMounted } = Vue; const App = { setup() { const mydiv = ref(null); const wrapperHeight = ref(0); const rangeValue = ref(50); onMounted(() => { console.log(`onMounted(): ${mydiv.value.offsetHeight}`); wrapperHeight.value = mydiv.value.offsetHeight; }); const updateHeight = (event) => { console.log(`updateHeight(): ${event.target.value}`); wrapperHeight.value = event.target.value; } return {mydiv, wrapperHeight, rangeValue, updateHeight } } } const app = createApp(App) app.mount('#app')
 <div id="app"> <input type="range" min="10" max="100" class="slider" v-model="rangeValue" @change="updateHeight" /><br/> rangeValue: {{rangeValue}} <br/> wrapperHeight: {{wrapperHeight}} <br/><br/> <div:style="{ 'background-color': 'yellow', 'min-height': `${wrapperHeight}px` }"> <div ref="mydiv" style="{ 'float': 'bottom' }">My Div</div> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM