Múltiples instancias de Vue en la misma página usando la misma base de código

5 minutos de lectura

avatar de usuario
sMyles

Estoy trabajando para llevar la funcionalidad de Vue.js al ecosistema de WordPress, y mi primer proyecto es para búsqueda y filtrado en una página.

Debido a que el sitio web principal está siendo renderizado inicialmente por WordPress con PHP/HTML, tengo Vue inicializándose en la página que se adjunta a un elemento HTML que emito usando WordPress. Todo esto funciona perfectamente bien, pero ahora estoy tratando de llevar esto un paso más allá al tener múltiples instancias de la misma base de código (que pueden funcionar juntas)

Tome esta captura de pantalla de ejemplo de hecho (suponga que este es un sitio de WordPress):
múltiples instancias de vue

Debido a que la salida completa no se realiza en Vue.js, tengo que generar múltiples elementos HTML DIV desde el lado de WordPress e inicializar Vue en ellos.

Debido a que el formulario/los campos se generarán dinámicamente en función de la configuración/configuración del usuario, se usaría la misma base de código para ambas instancias… pero de alguna manera necesito hacerlo para que puedan trabajar juntos al unísono, por ejemplo, actualizar los resultados. en la página, cuando se selecciona o cambia un valor, en cualquiera de las instancias.

La idea aquí está en mi archivo JS principal usando javascript vainilla para detectar todos mis elementos HTML específicos que existen en la página (tal vez incluso definir un slug para cada uno en un objeto de datos), y luego hacer un ciclo foreach para luego iniciar un new Vue() en cada instancia.

Mi primer pensamiento es usar el almacenamiento de Vuex, adjuntando el almacenamiento único a todas las instancias, almacenando los valores seleccionados y activando un envío para actualizar los listados cuando alguno de ellos cambie.

¿Alguien ha hecho algo similar a esto antes? ¿Hay algo por lo que deba preocuparme al hacer esto? ¿O alguien tiene mejores sugerencias sobre cómo se debe hacer esto?

Pensé que sería mejor para mí preguntar aquí en lugar de aprender de la manera difícil y luego descubrir más tarde que puede que no sea posible, o que habrá problemas al hacerlo.

Cualquier sugerencia, comentario, crítica o idea es muy apreciada.

actualizar
Tenía una sugerencia para simplemente vincular la instancia de Vue al cuerpo, eliminar el render función, y luego simplemente generar el elemento HTML del componente donde sea necesario (en lugar de generar un div y luego adjuntarlo). ¿Vas a probar esto, pero tienes curiosidad sobre los pensamientos que rodean esto?

  • Un autobús de eventos es lo que hay que mirar aquí. Con él, puede tener múltiples instancias de Vue (y sus componentes dentro) hablando entre sí. VueX también puede hacer el trabajo, pero muchos lo considerarían excesivo ya que no es un SPA.

    – Marte y la espalda

    22 de septiembre de 2020 a las 20:23

Para cualquiera que se encuentre con esto, terminé simplemente inicializando las instancias de Vue de esta manera:

const sections = document.getElementsByClassName( "my-wrapper" )

for ( var i = 0; i < sections.length; i ++ ) {
    new Vue( {
         el: '#' + sections[ i ].id,
         store
     })
}

Básicamente, inicializando una nueva instancia de Vue en cada salida encontrada en la página, pasando la tienda compartida a cada uno.

  • ¿Qué tan bien terminó funcionando esto para ti? (suponiendo que su proyecto avance)

    – Roberto

    2 de noviembre de 2021 a las 23:25

  • @robert funcionó muy bien todavía usándolo hoy, miles de instalaciones y ningún problema real “importante” que haya encontrado

    – sMyles

    5 de noviembre de 2021 a las 17:55

  • Gracias. ¡Es bueno escuchar! Me alejé de Vuex en mi trabajo de Vue3+, así que estoy considerando los mensajes entre instancias (como mkuehn aquí: foro.vuejs.org/t/…)

    – Roberto

    5 de noviembre de 2021 a las 21:24

Yo mismo no he realizado esta configuración de varias instancias de Vue, pero leí en un par de lugares que Vue está diseñado para admitir este caso de uso. Consulte, por ejemplo, aquí: Vue: ¿Están bien varias aplicaciones de Vue para un solo sitio web?

Vuex es excelente para un SPA más grande con múltiples componentes y lo que sugiere es esencialmente lo mismo sin una instancia raíz compartida entre todos los componentes. Aquí es donde la tienda de Vuex será muy útil al mantener todos los componentes de Vue en la página sincronizados con una única “fuente de la verdad” de los datos de la aplicación.

Aunque no estoy seguro de haber entendido esa parte de tu pregunta:

Mi primer pensamiento es usar el almacenamiento Vuex, adjuntar el almacenamiento único a todas las instancias, almacenar los valores seleccionados y activando un envío para actualizar los listados cuando alguno de ellos cambie.

Cuando los datos se actualizan en la tienda Vuex, si configura Vuex correctamente, las actualizaciones del DOM se realizarán de forma “reactiva” automáticamente. No hay ninguna acción a realizar más que modificar los datos de la tienda.

En cuanto a su actualización, tal vez funcione, pero no me parece una buena idea. Parece ir en contra de la forma en que se usa normalmente Vue y no recuerdo ninguna parte de la documentación que mencione tal configuración.

Como dije, no tengo experiencia directa con su diseño propuesto, por lo que es posible que me haya perdido algo. Pensé en compartir de todos modos.

para realizar más instancias de vue, debe separar los elementos a los que adjunta vue (observe los elementos el ) del siguiente código:

<div id="app" class="container">
        <my-component 
        v-for="(item,index) in array_2_element" 
        v-bind:item="item"
        v-bind:index="index"
        v-bind:key="item.name"
        > test componente <br> <my-component>
      </div>
      <hr><br>
  </div>
</div>

  <div id="todo-list-example">
    <form v-on:submit.prevent="addNewTodo">
      <label for="new-todo"> add a todo </label>
      <input type="text" 
      v-model="newTodoText"
      id="new-todo"
      placeholder="E.g. Feed to cat "
      >
      <button type="button" class="btn btn-primary"> add</button>
    </form>
    <ul>
      <li
      is="todo-item"
      v-for="(todo,index ) in todos "
      v-bind:key="todo.id"
      v-bind:title="todo.title"
      v-on:remove="todos.splice(index,1)"
      ></li>
    </ul>
  </div>

<script> 
    var vm2= new Vue({
    el: '#todo-list-example',
    // do somethings 
});

var vm = new Vue({
    el: '#app',
    // do somethings 
})
</script>

¿Ha sido útil esta solución?