Aplicaciones de una sola página con Vue.js y Flask: Navegando por el router de Vue

    Bienvenido a la segunda publicación sobre el uso de Vue.js y Flask para el desarrollo web de pila completa. El tema principal de este artículo será sobre Vue Router, pero también cubriré la directiva v-model, así como los métodos Vue y las propiedades calculadas. Dicho esto, toma algo con cafeína y consume un poco de bondad Vue. El código de esta publicación está en mi GitHub .

    Contenido de la serie

    • Configuración y familiarización con VueJS
    • Navegando Vue Router (estás aquí)
    • Gestión de estado con Vuex
    • API RESTful con Flask
    • Integración AJAX con API REST
    • Autenticación JWT
    • Implementación en un servidor privado virtual

    Familiarizarse con el enrutador Vue

    Como la mayoría de los otros aspectos del marco Vue.js, usar Vue Router para navegar por las distintas páginas y los componentes posteriores es increíblemente fácil.

    Aparte 1: instancias independientes de Vue y vue-router

    Algunos de los temas presentados en esta publicación se describirán mejor con ejemplos de juguetes más pequeños, por lo que habrá ocasiones en las que salga a un lado para hacerlo. Aparte de esto, demostraré lo que se requiere para colocar una instancia y un enrutador de Vue independientes. Si bien Vue es absolutamente fenomenal para crear aplicaciones SPA completas, también hay un valor real en la capacidad de colocarlo en una página HTML normal.

    <!-- index.html -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    
    <div id="app">
      <div>
        <h2>Cartoon characters</h2>
        <div v-for="(character, i) in characters" v-bind:key="i">
          <h4>{{ character.name }}</h4>
          <p><img v-bind:src="character.imgSrc" v-bind:alt="character.name"/></p>
        </div>
      </div>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        characters: [{
          name: 'Scooby',
          imgSrc: 'https://www.wbkidsgo.com/Portals/4/Images/Content/Characters/Scooby/characterArt-scooby-SD.png'
        }, {
          name: 'Shaggy',
          imgSrc: 'https://upload.wikimedia.org/wikipedia/en/thumb/8/87/ShaggyRogers.png/150px-ShaggyRogers.png'
        } ]
      }
    })
    
    </script>
    

    Esto muestra los personajes de dibujos animados Scooby y Shaggy. El ejemplo presenta la v-bind:directiva para vincular dinámicamente datos de la charactersmatriz a los atributos srcy altdel imgelemento, lo que permite que los datos dirijan el contenido. Esto es similar a cómo se realiza la interpolación de texto {{}}, excepto que v-bindinterpola los datos en atributos. Puede encontrar un ejemplo práctico de esto aquí .

    En lugar de mostrar ambos personajes, cambiemos nuestro enfoque, permitiéndonos hacer clic en un enlace para que cada personaje muestre un componente específico «Scooby» o «Shaggy». Para lograr esto, extraeré la biblioteca vue-router y realizaré los siguientes cambios:

    <!-- index.html -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    
    <div id="app">
      <p>
        <router-link to="/scooby">Scooby</router-link>
        <router-link to="/shaggy">Shaggy</router-link>
      </p>
      <router-view></router-view>
    </div>
    
    <script>
    const Scooby = {
      template: `
        <div>
          <h4>Scooby</h4>
          <p>
            <img src="https://www.wbkidsgo.com/Portals/4/Images/Content/Characters/Scooby/characterArt-scooby-SD.png" alt="scooby"/>
          </p>
        </div>`
    }
    
    const Shaggy = {
      template: `
        <div class="character">
            <h4>Shaggy</h4>
          <p><img src="https://upload.wikimedia.org/wikipedia/en/thumb/8/87/ShaggyRogers.png/150px-ShaggyRogers.png" alt="shaggy"/></p>
        </div>`
    }
    
    const router = new vue-router({
      routes: [
        { path: '/scooby', component: Scooby },
        { path: '/shaggy', component: Shaggy }
      ]
    })
    
    const app = new Vue({ router: router }).$mount('#app')
    </script>
    

    Como probablemente pueda ver, esta implementación está impulsada por componentes codificados, lo que no es un cambio beneficioso desde el punto de vista de la reutilización. Sin embargo, muestra un uso fácil de seguir de vue-router. Además de obtener la biblioteca vue-router, el HTML contiene dos nuevos elementos, componentes en realidad, específicos de vue-router.

    El primer componente vue-router es <router-link>el que recibe una ruta de ruta a través del toatributo, que en realidad se denomina «parámetro» en un componente Vue. El <router-link>componente produce un elemento de hipervínculo que responde a eventos de clic y le dice a Vue que muestre el componente asociado con su toparámetro, ya sea «/ scooby» o «/ shaggy».

    A continuación <router-link>se muestra otro componente nuevo <router-view>, que es donde vue-router le dice a Vue que inyecte los componentes de la interfaz de usuario, Scooby y Shaggy. Los componentes de la plantilla personalizada de Scooby y Shaggy se definen en el scriptelemento al final de esta página de ejemplo index.html.

    Te puede interesar:Creación de API GraphQL con Vue.js y Apollo Client

    A continuación, se crea una instancia de un routesobjeto vue-router con un objeto que define una matriz de rutas similar a la que vimos en la aplicación Survey del primer artículo. Aquí, las rutas de las rutas se asignan a los componentes Scooby y Shaggy. Lo último que debe hacer es crear una instancia de Vue, darle un objeto de enrutador como propiedad de su objeto de opciones y vincular la instancia a la aplicación div.

    Puede hacer clic en el enlace del enrutador Scooby o Shaggy para mostrarlos, como se muestra a continuación. El código de este ejemplo se puede encontrar aquí .

    Uso de vue-router para mostrar una encuesta individual

    De vuelta en la aplicación de encuestas, comencemos nuestra discusión echando un vistazo al archivo route / index.js.

    import Vue from 'vue'
    import Router from 'vue-router'
    import Home from '@/components/Home'
    
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path: "https://Pharos.sh.com/",
          name: 'Home',
          component: Home
        }
      ]
    })
    

    La página de inicio muestra las encuestas de la aplicación cuando se solicita la URL raíz en localhost: 8080 porque está asignada al Homecomponente a través de las rutas del enrutador.

    También necesito conectarme a Vue a través de la Vue.use(Router)función para una aplicación SPA modular como esta. Además, necesito incluir el enrutador en el objeto de opciones, que se alimenta a la instancia de Vue en main.js de manera similar al ejemplo del juguete Scooby / Shaggy.

    Continuando con la aplicación Encuesta, agrego una nueva ruta al routesobjeto que mapeará cada encuesta y sus preguntas a un componente reutilizable basado en el archivo Survey.vue. En el archivo routes / index.js, importe un Surveycomponente y luego agregue una ruta para mapear cada encuesta por su ID al Surveycomponente.

    // ... omitted for brevity
    import Survey from '@/components/Survey'
    
    // ... omitted for brevity
    
    export default new Router({
      routes: [
        {
          // ... omitted for brevity
        }, {
          path: '/surveys/:id',
          name: 'Survey',
          component: Survey
        }
      ]
    })
    

    Tenga en cuenta la :idparte de la nueva ruta /surveys/:id. Esto se conoce como un segmento dinámico que puede considerar como una variable dentro de una ruta. En este caso, estoy diciendo que :idse usará para identificar una encuesta específica para mostrar en el Surveycomponente que se construirá a continuación.

    En el directorio «src / components /», cree un archivo llamado Survey.vue, luego ábralo y agregue la plantilla estándar, el script y las secciones de estilo junto con el código que se muestra a continuación:

    <template>
    <div>
      <h2>I'm a Survey Component</h2>
    </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          survey: {}
        }
      },
      beforeMount() {
        console.log('Survey.beforeMount -> :id === ', this.$route.params.id)
      }
    }
    </script>
    
    <style>
    
    </style>
    

    Guardando todos los archivos e inicio el servidor de desarrollo con npm run dev, luego ingrese la siguiente URL en el navegador: localhost: 8080 / # / survey / 23. En la consola de las herramientas de desarrollo de mi navegador, veo la imagen a continuación.

    Te puede interesar:Operador de propagación en JavaScript

    Entonces, ¿qué acaba de pasar?

    En la templatesección, agregué un código sin sentido para dejar en claro que el enrutador está sirviendo el componente de encuesta. En la scriptsección, inicialicé un objeto de encuesta que eventualmente contendrá datos de encuesta. En el beforeMountgancho del ciclo de vida está sucediendo algo muy bueno. En esta función estoy accediendo a la ruta de la ventana actual y al :idparámetro posterior definido en el routemódulo.

    Esta última parte es posible porque el Surveyobjeto Vue del componente hace referencia a la instancia del enrutador vue que da acceso a la ruta que me permite acceder con ella this.$route.params.id. Una ruta puede tener múltiples segmentos dinámicos y todos son accesibles en sus componentes correspondientes a través del paramsmiembro del this.$routeobjeto.

    A continuación, definiré una función AJAX simulada en api / index.js, a la que llamo desde el gancho Surveydel componente beforeMountpara obtener una encuesta :id. En api / index.js agregue la siguiente función:

    const surveys = [{
      id: 1,
      name: 'Dogs',
      // ... omitted for brevity 
    }, {
      id: 2,
      name: 'Cars',
      // ... omitted for brevity 
    }]
    
    // ... omitted for brevity
    
    export function fetchSurvey (surveyId) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const survey = surveys.find(survey => survey.id === surveyId)
          if (survey) {
            resolve(survey)
          } else {
            reject(Error('Survey does not exist'))
          }
        }, 300)
      })
    }
    

    Ahora, de vuelta en el Surveycomponente, necesito importarlo fetchSurveyy usarlo beforeMountpara recuperar la encuesta solicitada. Una vez más, con fines visuales, mostraré el nombre de la encuesta en la plantilla como un encabezado de Bulma Hero.

    <template>
    <div>
        <section class="hero is-primary">
          <div class="hero-body">
            <div class="container has-text-centered">
              <h2 class="title">{{ survey.name }}</h2>
            </div>
          </div>
        </section>
    </div>
    </template>
    
    <script>
    import { fetchSurvey } from '@/api'
    export default {
      data() {
        return {
          survey: {}
        }
      },
      beforeMount() {
        fetchSurvey(parseInt(this.$route.params.id))
          .then((response) => {
            this.survey = response
          })
      }
    }
    </script>
    
    <style>
    </style>
    

    Actualizando la URL del navegador a localhost: 8080 / survey / 2, veo lo que se muestra a continuación:

    Bastante bien, ¿verdad?

    A continuación, me gustaría hacer algo un poco más útil con mi Surveycomponente e incluir las preguntas y opciones.

    <template>
      <div>
        <!-- omitted survey name header for brevity -->
    
        <section class="section">
          <div class="container">
    
            <div class="columns">
              <div class="column is-10 is-offset-1">
    
                <div v-for="question in survey.questions" v-bind:key="question.id">
    
                      <div class="column is-offset-3 is-6">
                        <h4 class="title has-text-centered">{{ question.text }}</h4>
                      </div>
                      <div class="column is-offset-4 is-4">
                        <div class="control">
                          <div v-for="choice in question.choices" v-bind:key="choice.id">
                            <label class="radio">
                            <input type="radio" v-model="question.choice" :value="choice.id">
                            {{ choice.text }}
                          </label>
                          </div>
                        </div>
                      </div>
    
                </div>
    
              </div>
            </div>
    
          </div>
        </section>
      </div>
    </template>
    

    Nuevamente, al guardar y actualizar el navegador con la URL localhost: 8080 / # / survey / 2 ahora se muestra una lista de preguntas y las opciones disponibles para la encuesta de autos.

    Te puede interesar:Funciones de flecha en JavaScript

    Permítanme intentar analizar algunas de las nuevas funciones de Vue que se están utilizando. Ya estamos familiarizados con el uso de la v-fordirectiva para impulsar la generación de las preguntas y opciones de la encuesta, por lo que es de esperar que pueda realizar un seguimiento de cómo se muestran. Sin embargo, si se concentra en cómo se generan los botones de opción para las opciones de una pregunta, notará que estoy haciendo dos cosas nuevas o ligeramente diferentes.

    <div v-for="choice in question.choices" v-bind:key="choice.id">
      <label class="radio">
        <input type="radio" v-model="question.choice" :value="choice.id">
        {{ choice.text }}
      </label>
    </div>
    

    Para la entrada de radio he utilizado la v-modeldirectiva y la he proporcionado con un valor de question.choice. Lo que hace esto es que crea un nuevo miembro en el questionobjeto llamado elección y lo registra con la entrada de radio, lo que permite que los datos fluyan desde la entrada de radio real a la question.choicepropiedad del objeto. También estoy usando una sintaxis abreviada de en :valuelugar de v-bind:valuevincular el valor de esta entrada de radio al valor de las opciones de pregunta que se repiten a través de v-for.

    Apartado 2: uso de la directiva del modelo v

    Me doy cuenta de que el v-modelconcepto probablemente sea un poco confuso, así que permítanme hacerme a un lado y dar otro ejemplo simple para demostrar el punto. Considere el ejemplo trivial a continuación. Nuevamente, puede ver un ejemplo funcional de este código aquí .

    <!-- index.html -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    
    <div id="app">
      <div>
        <label for="name">What is your name</label>
        <input id="name" type="text" v-model="textInput" />
        <span>Hello {{ textInput }}</span>
      </div>
    
      <h4>Which do you like better?</h4>
      <div v-for="choice in radioChoices" :key="choice">
        <label>{{ choice }}</label>
        <input name="fruit" type="radio" v-model="favoriteFruit" :value="choice"/>
      </div>
      <h4>So you like {{ favoriteFruit }}</h4>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        textInput: '',
        radioChoices: ['apples', 'oranges'],
        favoriteFruit: ''
      }
    })
    </script>
    

    La primera entrada es una entrada de texto que solicita el nombre del usuario. Esta entrada de texto tiene un v-modelregistro con la propiedad de datos textInputadjunta, lo que mantiene la entrada de texto sincronizada con la textInputpropiedad de datos de la Vueinstancia. Tómese un segundo para escribir su nombre en la entrada de texto y observe cómo se actualiza en la <span>Hello {{ textInput }}</span>salida del HTML.

    Increíble verdad?

    La segunda entrada es una entrada de radio llamada «fruta» que muestra las frutas «manzanas» y «naranjas» y le pide al usuario que seleccione su favorito. La entrada de radio se registra en la favoriteFruitpropiedad de datos de la Vueinstancia a través de v-model, que asocia el valor asociado con cada entrada de radio a través de la :value="choice"sintaxis de enlace de atributos para mantener la favoriteFruitsincronización con la entrada de radio seleccionada. Nuevamente, puede observar el valor de favoriteFruitactualización en la <h4>So you like {{ favoriteFruit }}</h4>salida del elemento.

    A continuación muestro el resultado de algunos ejemplos. Te animo a que juegues con este ejemplo hasta que la noción de v-modelsea ​​clara.

    Completar la experiencia de realización de encuestas

    Ok, volvamos a la aplicación de encuestas. Piense en el caso en el que una encuesta tiene muchas más preguntas debajo de la altura de pantalla predeterminada. En general, queremos evitar que las personas tengan que desplazarse hacia abajo para ver su contenido más importante. Una mejor opción sería paginar las preguntas que muestran una pregunta y sus respuestas, a la vez.

    Te puede interesar:Envío de solicitudes AJAX en Vue.js

    El Surveycomponente actualizado logra esto a continuación.

    <template>
      <div>
        <!-- omitted for brevity -->
        <section class="section">
          <div class="container">
    
            <div class="columns">
              <div class="column is-10 is-offset-1">
    
                <div
                  v-for="(question, idx) in survey.questions" <!-- modified v-for -->
                  v-bind:key="question.id"
                  v-show="currentQuestion === idx"> <!-- new v-show directive -->
    
                      <div class="column is-offset-3 is-6">
                        <!-- <h4 class="title">{{ idx }}) {{ question.text }}</h4> -->
                        <h4 class="title has-text-centered">{{ question.text }}</h4>
                      </div>
                      <div class="column is-offset-4 is-4">
                        <div class="control">
                          <div v-for="choice in question.choices" v-bind:key="choice.id">
                            <label class="radio">
                            <input type="radio" v-model="question.choice" :value="choice.id">
                            {{ choice.text }}
                            </label>
                          </div>
                        </div>
                      </div>
    
                </div>
    
                <!-- new pagination buttons -->
                <div class="column is-offset-one-quarter is-half">
                  <nav class="pagination is-centered" role="navigation" aria-label="pagination">
                    <a class="pagination-previous" @click.stop="goToPreviousQuestion"><i class="fa fa-chevron-left" aria-hidden="true"></i> &nbsp;&nbsp; Back</a>
                    <a class="pagination-next" @click.stop="goToNextQuestion">Next &nbsp;&nbsp; <i class="fa fa-chevron-right" aria-hidden="true"></i></a>
                  </nav>
                </div>
    
                <!-- new submit button -->
                <div class="column has-text-centered">
                  <a v-if="surveyComplete" class="button is-focused is-primary is-large"
                    @click.stop="handleSubmit">
                    Submit
                  </a>
                </div>
    
              </div>
            </div>
    
          </div>
        </section>
      </div>
    </template>
    
    <script>
    import { fetchSurvey, saveSurveyResponse } from '@/api' // new AJAX func
    export default {
      data() {
        return {
          survey: {},
          currentQuestion: 0  // new data prop
        }
      },
      beforeMount() {
        // omitted for brevity
      },
      methods: { // new Vue obj member
        goToNextQuestion() {
          if (this.currentQuestion === this.survey.questions.length - 1) {
            this.currentQuestion = 0
          } else {
            this.currentQuestion++
          }
        },
        goToPreviousQuestion() {
          if (this.currentQuestion === 0) {
            this.currentQuestion = this.survey.questions.lenth - 1
          } else {
            this.currentQuestion--
          }
        },
        handleSubmit() {
          saveSurveyResponse(this.survey)
            .then(() => this.$router.push("https://Pharos.sh.com/"))
        }
      },
      computed: {  // new Vue obj member
        surveyComplete() {
          if (this.survey.questions) {
            const numQuestions = this.survey.questions.length
            const numCompleted = this.survey.questions.filter(q => q.choice).length
            return numQuestions === numCompleted
          }
          return false
        }
      }
    }
    </script>
    

    Estos cambios funcionan en conjunto para completar la experiencia de realización de encuestas. Como se generan los nodos de preguntas v-for="(question, idx) in survey.questions", estoy usando la v-show="currentQuestion === idx"directiva para probar si el valor de la propiedad de datos currentQuestioncoincide con el valor de idx. Esto hace que la pregunta sea divvisible solo si currentQuestiones igual al idxvalor de esa pregunta . Dado que el valor de currectQuestionse inicializa a cero, la pregunta cero se mostrará de forma predeterminada.

    Debajo de las preguntas y respuestas, los botones de paginación permiten al usuario paginar las preguntas. El elemento de botón «siguiente» tiene @click="goToNextQuestion"dentro de él, que es un controlador de eventos de clic de Vue que responde llamando a la goToNextQuestionfunción dentro de la nueva methodspropiedad del objeto Vue. La methodssección de un objeto componente de Vue es donde se pueden definir funciones para hacer una serie de cosas, la mayoría de las veces para cambiar el estado del componente. Aquí goToNextQuestionaumenta currentQuestionen uno, avanzando la pregunta que se muestra, o la restablece a la primera pregunta. El botón de retroceso y su goToPreviousQuestionmétodo asociado hacen exactamente lo contrario.

    El último cambio es la funcionalidad para enviar la respuesta de la encuesta. El botón se usa v-shownuevamente para determinar si el botón debe mostrarse en función del valor de una propiedad calculada llamada surveyCompleted. Las propiedades computadas son otro rasgo asombroso de Vue. Son propiedades que generalmente controlan cómo se muestran los componentes de la interfaz de usuario que son útiles cuando la lógica es un poco más compleja que verificar un solo valor de una propiedad de datos. De esta manera, el código de la plantilla está limpio y puede enfocarse en la presentación mientras la lógica permanece en el código JavaScript.

    Un detector de eventos de clic,, @click="handleSubmit"se registra en el botón de anclaje de envío, que llama al handleSubmitmétodo. Este método llama a la función simulada AJAX saveSurveyResponse, que devuelve una promesa y pasa el control a la «cadena entonces». La «cadena entonces» tiene una devolución de llamada, .then(() -> this.$router.push("https://Pharos.sh.com/"))que llama al objeto enrutador del componente y enruta mediante programación la aplicación de regreso a la ruta raíz que muestra el Homecomponente.

    En api / index.js agregue la saveSurveyResponsefunción al final del archivo. Esta función recibe un objeto de respuesta a la encuesta y simplemente registra en la consola «guardando la respuesta de la encuesta …» hasta que conecte el front-end a la API REST en el futuro.

    export function saveSurveyResponse (surveyResponse) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log("saving survey response...")
          })
          resolve()
        }, 300)
      })
    }
    

    Guardando todos los archivos y actualizando el navegador con la URL localhost: 8080: / # / survey / 2 Veo lo que hay a continuación. Recomiendo hacer clic en la aplicación y asegurarse de que pueda rastrear lógicamente el flujo de control a través del Surveycomponente.

    Aparte 3 – Enrutamiento programático

    Al igual que antes, quiero demostrar algunas cosas que acabo de discutir con una variación de uno de los ejemplos de juguetes anteriores. A continuación, he modificado el ejemplo de navegación que muestra Scooby o Shaggy para que ya no utilicen el <router-link>componente.

    Te puede interesar:Eliminar elemento de una matriz en JavaScript
    <!-- index.html -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    
    <div id="app">
      <p>
        <a @click="toScooby">Scooby</a>
        <a @click="toShaggy">Shaggy</a>
      </p>
      <router-view></router-view>
    </div>
    
    <script>
    const Scooby = {
        template: `
        <div>
          <h4>Scooby</h4>
          <p>
            <img src="https://www.wbkidsgo.com/Portals/4/Images/Content/Characters/Scooby/characterArt-scooby-SD.png" alt="scooby"/>
          </p>
        </div>`
    }
    
    const Shaggy = {
        template: `
        <div class="character">
          <h4>Shaggy</h4>
          <p>
            <img src="https://upload.wikimedia.org/wikipedia/en/thumb/8/87/ShaggyRogers.png/150px-ShaggyRogers.png" alt="shaggy"/>
          </p>
        </div>`
    }
    
    const router = new vue-router({
      routes: [
        { path: '/characters/scooby', component: Scooby },
        { path: '/characters/shaggy', component: Shaggy }
      ]
    })
    
    const app = new Vue({
      router: router,
      methods: {
        toScooby() { this.$router.push('/characters/scooby') },
        toShaggy() { this.$router.push('/characters/shaggy') }
      }
    }).$mount('#app')
    
    </script>
    

    El ejemplo se comporta exactamente de la misma manera que antes, pero ahora el enrutamiento se realiza mediante una combinación de detectores de eventos de clic, métodos Vue y llamadas manuales this.$router.push('/path'). Esto es realmente lo que <router-link>hace detrás de escena usando el to="/path"valor. Te animo a jugar con este ejemplo en vivo aquí .

    Agregar enlaces de enrutador al componente de inicio

    Lo último que se puede hacer con el Surveycomponente es proporcionar la capacidad de navegar a una encuesta desde el Homecomponente. Como se mostró anteriormente con el ejemplo de Scooby y Shaggy, vue-router hace que esto sea increíblemente fácil con <router-link>.

    De vuelta en el Homecomponente, realice la siguiente modificación:

    <div class="card" v-for="survey in surveys" v-bind:key="survey.id">
      <div class="card-content">
        <p class="title">{{ survey.name}}</p>
        <p class="subtitle">{{survey.created_at.toDateString()}}</p>
      </div>
      <div class="card-foooter">
        <router-link :to="`surveys/${survey.id}`" class="card-footer-item">Take Survey</router-link>
      </div>
    </div>
    

    <router-link>Agregué un componente dentro de un pie de página de tarjeta bulma y construí dinámicamente la ruta a cada encuesta. Esto es diferente de las rutas de cadena literales que proporcioné en mi ejemplo anterior. Para producir dinámicamente las rutas usando las cadenas de plantilla de JavaScript y las ID de encuesta que se iteran, prefijo el toparámetro con dos puntos («:»), que es la abreviatura de la v-binddirectiva.

    Guardo todos los archivos y busco la ruta de la URL raíz, localhost: 8080, en mi navegador para asegurarme de que funciona. Debería poder hacer clic en el enlace «Realizar encuesta» de cada encuesta y se mostrará la Surveyinterfaz de usuario del componente.

    Para completar la experiencia, agrego una barra de navegación simple con una pestaña «Inicio» usando <router-link>y un toparámetro que apunta a la ruta raíz de la aplicación dentro de un nuevo archivo de componente llamado Header.vue en el directorio del componente.

    <template>
    <nav class="navbar is-light" role="navigation" aria-label="main navigation">
      <div class="navbar-menu">
        <div class="navbar-start">
          <router-link to="/" class="navbar-item">
            Home
          </router-link>
        </div>
      </div>
    </nav>
    </template>
    
    <script>
    </script>
    
    <style>
    </style>
    

    Para asegurarme de que esté incluido en todas las páginas de la aplicación, lo coloco en el componente App.vue. Para hacer esto, primero importo el Headercomponente como AppHeaderen la scriptsección y luego lo registro agregando una propiedad llamada componentsen el objeto Vue del componente de la aplicación y lo configuro igual a un objeto que contiene el AppHeadercomponente.

    Luego agrego el componente en la plantilla colocándolo <app-header>justo encima del <router-view>componente. Al nombrar componentes, es común usar el caso Pascal concatenando las palabras que lo describen juntas, donde la primera letra de cada palabra está en mayúscula. Luego lo incluyo en la plantilla en minúsculas con guiones entre cada palabra que comienza con una letra en mayúscula.

    Al guardar los archivos y actualizar el navegador, ahora veo el Headercomponente que contiene la barra de navegación en cada página de la aplicación.

    Te puede interesar:Cómo usar module.exports en Node.js

    Conclusión

    Si todavía está leyendo esto, ha consumido bastante bondad de Vue. Ciertamente cubrimos mucho material en esta publicación y si es nuevo en Vue o en los SPA de componentes de un solo archivo, probablemente valga la pena una segunda lectura y un viaje a los excelentes documentos de Vue para una inmersión más profunda.

    Como siempre, gracias por leer y no dude en comentar o criticar a continuación..

    Rate this post

    Etiquetas: