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.

    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.

    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.

    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 鈥嬧媍lara.

    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.

    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.

    <!-- 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.

    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..

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *