¿Cómo puedo controlar el cambio de tamaño de ventana en Vue?

6 minutos de lectura

avatar de usuario de bbsimonbb
bbsimonbb

En mi aplicación web móvil con Vue, quiero ocultar mi pie de página cuando aparece el teclado virtual. Así que tengo una pequeña función para probar la relación entre la altura de la ventana y el ancho de la ventana…

showFooter(){
    return h / w > 1.2 || h > 560;
}

…y declaro window.innerHeight/window.innerWidth en mis datos.

    data: { h: window.innerHeight, w: window.innerWidth }

El problema es que cuando cambia window.innerHeight, mi propiedad h no obtiene el nuevo valor. ¿Cómo puedo ver window.innerHeight?

  • En lugar de hacerlo en función del ancho/alto de la ventana, ¿no podría hacerlo en el enfoque de entrada/selección/área de texto?

    – Dan Gamble

    10 de noviembre de 2017 a las 9:33

avatar de usuario de samayo
samayo

Para obtener la altura actual de la ventana de su navegador a medida que cambia, use este script:

new Vue({
  el: '#app',
  data() {
    return {
      windowHeight: window.innerHeight
    }
  },

  mounted() {
    this.$nextTick(() => {
      window.addEventListener('resize', this.onResize);
    })
  },

  beforeDestroy() { 
    window.removeEventListener('resize', this.onResize); 
  },

  methods: {  
    onResize() {
      this.windowHeight = window.innerHeight
    }
  }
});

Cómo mostrar la información:

<div id="app">
 Current height: {{ windowHeight }}
</div>

  • Solo un recordatorio para usar algo como beforeDestroy() { window.removeEventListener('scroll', this.onScrollFunction); } Destaco aún más el uso del mismo cuando se trata de un SPA.

    – Marlon Barcarol

    10 de julio de 2018 a las 17:25


  • @MarlonBarcarol ¿Por qué es esto necesario?

    – Chris Jung

    18 de septiembre de 2019 a las 8:14

  • Es necesario porque a medida que se mueve entre los componentes, terminará con cientos o miles de detectores de eventos registrados que consumirán memoria y ralentizarán el navegador. En cambio, cuando se elimina (destruye) un componente, desea eliminar cualquier detector de eventos relacionado con ese componente, ya que ya no es necesario.

    – John Mellor

    19 de octubre de 2019 a las 4:34

  • Crucialmente, debe hacer esto porque el oyente está en el ventanano el componente que se destruye.

    – Darvanen

    18 dic 2019 a las 21:41

  • Por que es $nextTick necesario aquí?

    –Dylan Landry

    1 de febrero de 2021 a las 16:46

avatar de usuario de kshksdrt
kshksdrt

VUE 2.7 y superior

En Vue 2.7+, puede crear un componible que devuelva un ancho reactivo y un nombre de punto de interrupción.

import { computed, onMounted, onUnmounted, ref } from "vue"

export const useBreakpoints = () => {
  let windowWidth = ref(window.innerWidth)

  const onWidthChange = () => windowWidth.value = window.innerWidth
  onMounted(() => window.addEventListener('resize', onWidthChange))
  onUnmounted(() => window.removeEventListener('resize', onWidthChange))
  
  const type = computed(() => {
    if (windowWidth.value < 550) return 'xs'
    if (windowWidth.value >= 550 && windowWidth.value < 1200) return 'md'
    if (windowWidth.value >= 1200) return 'lg'
    return null; // This is an unreachable line, simply to keep eslint happy.
  })

  const width = computed(() => windowWidth.value)

  return { width, type }
}

Puede usarlo en el método de configuración de sus componentes.

const { width, type } = useBreakpoints()

Sugerencia rápida: por motivos de rendimiento, es mejor utilizarlo solo una vez en una aplicación por motivos de rendimiento.

  • Cree un pequeño complemento y agregue el valor a la instancia de Vue, tal como lo hace Vuetify.

  • O use proporcionar e inyectar.

  • O comprométalos con su solución de administración de estado glabal.

  • Esto no funcionó para mí, recibí el siguiente error: 10:25 error Expected to return a value in computed function vue/return-in-computed-property

    – DmnkVD

    3 de diciembre de 2021 a las 19:38


  • Tiene que ser una regla eslint. Eslint no puede inferir que siempre habrá un valor de retorno aquí. Eslint es conocido por estos casos. Puede agregar con seguridad un “ignorar eslint” para esta línea/archivo.

    – kshksdrt

    4 de diciembre de 2021 a las 9:28

  • Muchas gracias por aclarar! ¿Habría también una forma de importar esta función de utilidad en un componente que no está escrito con setup() (usa Opciones)?

    – DmnkVD

    4 de diciembre de 2021 a las 10:34


  • Tiene que ser utilizado en un método de configuración. Puede crear un nuevo método de configuración, llamar a la función y devolverla. Es muy normal usar tanto la api de composición como la api de opciones en el mismo componente.

    – kshksdrt

    5 de diciembre de 2021 a las 8:54

  • Hola, estoy tratando de hacer que esto funcione en mi proyecto y tengo algunos problemas para entender cómo usar este complemento. Realmente solo estoy buscando el ancho, pero he usado todo el código que escribiste. He descargado la parte superior del código en un window-width.ts archivo y estoy tratando de acceder a ellos en otro componente. Realmente no estoy entendiendo la desestructuración utilizada en su const { width, type } = useBreakpoints() Todavía soy un poco nuevo en Vue y en el uso de complementos, por lo que tal vez sea solo un malentendido fundamental, pero si tiene alguna idea, ¡realmente lo apreciaría!

    – LovelyAndy

    15 de diciembre de 2021 a las 15:59

avatar de usuario de cub33
cachorro33

La respuesta anterior no funcionó para mí. En cambio, usé:

mounted() {
  window.addEventListener('resize', () => {
    this.windowHeight = window.innerHeight
  })
}

  • algo anda mal con tus corchetes. window.addEventListener('resize', () => { this.windowHeight = window.innerHeight });

    – mvandillen

    24 de junio de 2020 a las 8:33

Para aquellos que ya usan Vuetify, solo pueden mirar this.$vuetify.breakpoint.width o this.$vuetify.breakpoint.height para cambios en las dimensiones de la ventana gráfica.

Documentos de punto de interrupción de Vuetify

Avatar de usuario de Shulz
Shulz

Probablemente sea demasiado tarde, pero si desea un enfoque mucho más simple, puede realizar la instalación de npm https://www.npmjs.com/package/vue-window-size
y import windowWidth from 'vue-window-size';

O esto con la api de composición

    setup() {
        const windowSize = ref(window.innerWidth)
        onMounted(() => {
            window.addEventListener('resize', () => {windowSize.value = window.innerWidth} )
        })
        onUnmounted(() => {
            window.removeEventListener('resize', () => {windowSize.value = window.innerWidth})
        })
        return { 
            windowSize
        }
    }

  • ¡Nunca demasiado tarde!

    – bbsimonbb

    10 de junio de 2021 a las 7:35

  • Necesitas crear una función y usarla en oyentes. En su ejemplo, agrega un oyente y elimina un oyente a diferentes funciones, es decir, eliminar el evento no funcionará. window.addEventListener('resize', func), window.removeEventListener('resize', func)

    – n4ks

    22 de febrero de 2022 a las 0:38


Avatar de usuario de Kaloyan Nikolov
Kaloyan Nikolov

Mi respuesta puede llegar tarde, pero ninguno de los anteriores funcionó para mí, ¡así que esto es lo que encontré sobre este tema! 🙂

https://codepen.io/sethdavis512/pen/EvNKWw

html:

<div id="app">
    <section class="section has-text-centered">
        <h1 class="title is-1">
            Your Window
        </h1>
        <h3 class="title is-3">
            Width: {{ window.width }} px<br/>
            Height: {{ window.height }} px
        </h3>
        <p class="has-text-white">
            &uarr;<br/>
            &larr; resize window &rarr;<br/>
            &darr;
        </p>
    </section>
</div>

CSS:

$top-color: yellow;
$bottom-color: tomato;

html, body, #app, section.section {
  height: 100%;
}

body {
    background: -webkit-linear-gradient($top-color, $bottom-color);
    background: -o-linear-gradient($top-color, $bottom-color);
    background: -moz-linear-gradient($top-color, $bottom-color);
    background: linear-gradient($top-color, $bottom-color);
}

section.section {
  display: flex;
  flex-flow: column;
  justify-content: center;
  align-items: center;
}

.title {
    color: white;
}

JS:

new Vue({
    el: '#app',
    data: {
        window: {
            width: 0,
            height: 0
        }
    },
    created() {
        window.addEventListener('resize', this.handleResize);
        this.handleResize();
    },
    destroyed() {
        window.removeEventListener('resize', this.handleResize);
    },
    methods: {
        handleResize() {
            this.window.width = window.innerWidth;
            this.window.height = window.innerHeight;
        }
    }
});

  • ¡Nunca demasiado tarde!

    – bbsimonbb

    10 de junio de 2021 a las 7:35

  • Necesitas crear una función y usarla en oyentes. En su ejemplo, agrega un oyente y elimina un oyente a diferentes funciones, es decir, eliminar el evento no funcionará. window.addEventListener('resize', func), window.removeEventListener('resize', func)

    – n4ks

    22 de febrero de 2022 a las 0:38


¿Ha sido útil esta solución?