Aplicaciones de una sola página con Vue.js y Flask: Configuración de Vue.js

A

Configuración y familiarización con Vue.js

Introducción

Esta es la publicación de apertura de una serie de tutoriales sobre el uso de Vue.js y Flask para el desarrollo web de pila completa. En esta serie, voy a demostrar cómo crear una aplicación web de encuestas donde la arquitectura de la aplicación consiste en un front-end compuesto por una aplicación de página única (SPA) Vue.js y una API REST de backend utilizando el marco web Flask.

Esta primera publicación cubrirá la configuración y estructura básicas del proyecto, utilizando la directiva Vue.js v-for y las etapas del ciclo de vida de los componentes.

Contenido de la serie

  • Configuración y familiarización con Vue.js (está aquí)
  • Navegando por el enrutador Vue
  • 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

Configuración de frontend con vue-cli y webpack

Usaré dos herramientas muy importantes para un proyecto de Vue.js, que son la interfaz de línea de comandos (CLI) oficial de Vue.js y el paquete web de herramientas de compilación y paquete de módulos muy poderoso . Ambas herramientas se basan en el tiempo de ejecución de Node.js y su administrador de paquetes, npm . Si aún no ha instalado el nodo, consulte los documentos de instalación de Node.js para su sistema, que también incluirán una instalación de npm.

Instale Vue.js CL (vue-cli):

$ npm install vue-cli -g

Ahora, con la CLI instalada, la usaré para inicializar una aplicación Vue.js SPA. La CLI hace lo siguiente:

  • Instalar y configurar webpack para empaquetar mi código
  • Instale un servidor de desarrollo con recarga en caliente (el servidor se reinicia automáticamente cuando se cambia un archivo)
  • Agregar una dependencia para vue-router
  • Realice una estructura de archivos SPA de Vue.js básica

Primero creo una carpeta de alto nivel que contendrá todo el código para este tutorial llamado “encuesta”. A continuación, hago dos directorios más llamados “frontend” (para Vue.js SPA) y “backend” (para desarrollar la API REST) ​​y luego cambio mi directorio de trabajo al directorio de frontend.

$ mkdir survey
$ cd survey
$ mkdir frontend
$ mkdir backend
$ cd frontend

Ahora la verdadera magia. Se ingresa el comando de inicialización de Vue CLI, que luego me pide que responda una serie de preguntas.

Presione enter aceptando los valores predeterminados para las preguntas (i) Nombre del proyecto, (ii) Descripción del proyecto, (iii) Autor del proyecto, (iv) Construir independiente. Cuando se le solicite instalar vue-router, ingrese “Y” para sí. Ingrese “n” para las entradas restantes y acepte los valores predeterminados.

$ vue init webpack survey-spa

? Project name survey-spa
? Project description A Vue.js project
? Author Adam McQuistan <[email protected]>
? Vue build standalone
? Install vue-router? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

   vue-cli · Generated "survey-spa".


# Installing project dependencies ...
...

Ahora debería haber un nuevo directorio llamado “survey-spa”. Cambie los directorios a este directorio y emita un comando npm para compilar el proyecto y lanzar el servidor de desarrollo.

$ cd survey-spa
$ npm run dev

Ahora puedo ingresar http: // localhost: 8080 en la ventana de mi navegador y debería ver la página de plantilla Vue.js repetitiva similar a la que se muestra a continuación.

La estructura de archivo que se creó se parece a la que se muestra a continuación. He omitido a propósito el atolladero de tonterías dentro de la carpeta node_modules.

survey-spa/
├── README.md
├── build
│   ├── build.js
│   ├── check-versions.js
│   ├── logo.png
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   └── webpack.prod.conf.js
├── config
│   ├── dev.env.js
│   ├── index.js
│   └── prod.env.js
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   ├── main.js
│   └── router
│       └── index.js
└── static

Es probable que esto parezca un poco abrumador las primeras veces que lo mires, pero no temas, solo debemos preocuparnos por los archivos del directorio src /, más el archivo index.html. Por supuesto, los otros archivos son importantes y quizás algún día me adentre en para qué se utilizan, pero por ahora ignórelos.

Los archivos en el directorio src / son donde escribiré el código para impulsar la funcionalidad de la aplicación. Abramos estos archivos y tengamos una idea de lo que está sucediendo.

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>survey-spa</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

Este es el único archivo HTML que utiliza un Vue SPA y rara vez contiene mucho más de lo que se muestra arriba, con la excepción de que a veces se vinculará a marcos CSS y otras bibliotecas de JavaScript dentro de este archivo. El único divelemento que se produce con un valor predeterminado idde “aplicación” es al que se adjuntará la instancia principal de Vue. Ese objeto Vue inyecta el HTML y CSS que están en los componentes, que se discutirán más adelante, en el divpara producir la interfaz de usuario.

main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

El archivo main.js es el punto de entrada principal para la aplicación y es donde registrará la instancia de Vue y las extensiones como vue-router y vuex . Como puede ver, aquí es donde reside la instancia de Vue. La instancia se registra en la aplicación divdiscutida anteriormente, además de que se alimenta el objeto del enrutador y el Appcomponente de alto nivel .

Ver aplicación

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

El archivo App.vue sirve como los componentes de la aplicación de nivel superior y, a menudo, contiene el diseño general de la aplicación. Los componentes de Vue tienen una estructura específica que contiene una <template>sección para HTML específico del componente, una <script>sección para definir el Vueobjeto y los comportamientos de ese componente implementados en JavaScript, y una <styles>sección para reglas CSS / SCSS. Sin embargo, ese último bit puede ser un poco confuso porque, de manera predeterminada, las reglas de estilo que define en un componente no solo pertenecen a ese componente. De hecho, afectan a todos los elementos de todo el proyecto a menos que agregue un scopedatributo al <style>elemento.

enrutador / index.js

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: "https://Pharos.sh.com/",
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

El script index.js en el directorio del enrutador es donde se definen las URL de la aplicación y se asignan a los componentes. Las dos primeras líneas importan los objetos Vuey Router, que luego están vinculados por el usemétodo en el Vueobjeto.

La ruta predeterminada que se proporciona desde la plantilla de paquete web vue-cli es simplemente la ruta raíz o de índice para la aplicación, que sirve al HelloWorldcomponente. Para mapear una ruta de ruta a un componente, primero debe importarse, luego debe definir un objeto de ruta en la routesmatriz dándole una ruta, un nombre y el componente que se mostrará.

componentes / HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li>
        <a href="https://vuejs.org" target="_blank">Core Docs</a>
      </li>
      <li>
        <a href="https://forum.vuejs.org" target="_blank">Forum</a>
      </li>
      <li>
        <a href="https://chat.vuejs.org" target="_blank">Community Chat</a>
      </li>
      <li>
        <a href="https://twitter.com/vuejs" target="_blank">Twitter</a>
      </li>
      <br>
      <li>
        <a href="http://vuejs-templates.github.io/webpack/" target="_blank">
          Docs for This Template
        </a>
      </li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li>
        <a href="http://router.vuejs.org/" target="_blank">vue-router</a>
      </li>
      <li>
        <a href="http://vuex.vuejs.org/" target="_blank">vuex</a>
      </li>
      <li>
        <a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a>
      </li>
      <li>
        <a href="https://github.com/vuejs/awesome-vue" target="_blank">
          awesome-vue
        </a>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

El directorio “componentes” es donde residen los componentes de la interfaz de usuario. El HelloWorldcomponente anterior nuevamente contiene la plantilla, el script y el estilo de tres secciones básicas, que tienen algún contenido de ejemplo de la plantilla de inicialización vue-cli.

Eche un vistazo al contenido de la sección de guiones. Aquí verá que se está exportando un objeto. Este objeto se inyectará en la Vueinstancia que se inicializó en el archivo main.js. Dentro de este objeto de JavaScript hay un datamétodo que devuelve un objeto. Este objeto es donde puede colocar el estado a nivel de componente (datos) y en este ejemplo es una propiedad única llamada msg.

Puede acceder y mostrar el estado de su componente por su nombre de propiedad dentro del HTML en la sección de plantilla. En el ejemplo proporcionado, verá esto como {{ msg }}. Los corchetes dobles son la sintaxis de la plantilla predeterminada para realizar la interpolación de texto y están inspirados en el sistema de plantillas Moustache . Cada vez que desee mostrar datos en el HTML de su componente, envuélvalos entre corchetes dobles.

Traer algo de estilo

Para darle a esta aplicación un mejor atractivo exterior, utilizaré el marco CSS de Bulma . El objetivo de este tutorial no será cómo usar Bulma, pero aún quiero incluirlo para evitar el aspecto monótono del HTML sin estilo.

De vuelta en la terminal en el mismo directorio que el archivo package.json, instale y guarde Bulma en el proyecto con el siguiente comando:

$ npm install --save bulma

Además, necesitaré instalar algunas herramientas de desarrollo para cargar correctamente los estilos de la aplicación para que los componentes sepan cómo trabajar con ellos. Para hacer esto, npm instala estos paquetes adicionales.

$ npm install --save-dev vue-style-loader
$ npm install --save-dev css-loader
$ npm install --save-dev sass-loader
$ npm install --save-dev node-sass

Ahora abra App.vue y reemplace la sección de estilo con lo que se muestra a continuación, que importará el marco de bulma usando la sintaxis de importación scss.

<style lang="scss">
@import '~bulma/bulma'
</style>

Dale una casa (página)

Bien, ahora que tenemos una comprensión básica de la estructura y las partes principales de una aplicación Vue.js SPA, puedo comenzar a escribir código.

Comience cambiando el nombre del archivo HelloWorld.vue a Home.vue y luego borre el contenido de las secciones de plantilla, script y estilo. Además, en App.vue, elimine la línea del logotipo de la imagen de Vue <img src="./assets/logo.png">y borre el contenido del <style>elemento mientras está allí. Por último, abra router / index.js e importe el componente Home.vue en lugar de HelloWorld.vue y actualice el objeto de ruta para usar el componente Home.

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
    }
  ]
})

Ahora abra el archivo Home.vue y complete la sección del script con lo que se muestra a continuación.

export default {
  data() {
    return {
      surveys: [{
      id: 1,
      name: 'Dogs',
      created_at: new Date(2017, 12, 1),
      questions: [
        {
          id: 1,
          text: 'What is your favorite dog?',
          choices: [
            { id: 1, text: 'Beagle', selected: 0 },
            { id: 2, text: 'Labrador', selected: 0 },
            { id: 3, text: 'Rottweiler', selected: 0 }]
        }, {
          id: 2,
          text: 'What is your second favorite dog?',
          choices: [
            { id: 5, text: 'Beagle', selected: 0 },
            { id: 6, text: 'Labrador', selected: 0 },
            { id: 7, text: 'Rottweiler', selected: 0 }]
        }]
      }, {
        id: 2,
        name: 'Cars',
        created_at: new Date(2017, 12, 3),
        questions: [
          {
            id: 5,
            text: 'What is your favorite car?',
            choices: [
              { id: 17, text: 'Corvette', selected: 0 },
              { id: 18, text: 'Mustang', selected: 0 },
              { id: 19, text: 'Camaro', selected: 0 }]
          }, {
            id: 6,
            text: 'What is your second favorite car?',
            choices: [
              { id: 21, text: 'Corvette', selected: 0 },
              { id: 22, text: 'Mustang', selected: 0 },
              { id: 23, text: 'Camaro', selected: 0 }]
          }]
      }]
    }
  }
}

Esto nos da algunos datos ficticios con los que trabajar. Como probablemente pueda ver, representa dos encuestas, una sobre perros y otra sobre automóviles. Los datos proporcionarán la unidad detrás del HTML que estamos a punto de escribir al proporcionar contenido para mostrar.

Ahora, en la sección de plantillas, agregaré un divque envolverá todos mis otros elementos. Cada componente de Vue debe tener un solo elemento principal, no puede haber elementos hermanos de nivel superior o el componente no se compilará. Dentro de este div, agregaré una sección para un encabezado de héroe de Bulma .

Debajo del encabezado habrá otra sección para mostrar el nombre de cada encuesta y la fecha en que se creó. Es en este bloque de HTML donde comenzaremos a ver algunas de las maravillas que proporciona Vue.js.

<template>
<div>
  <section class="hero is-primary">
    <div class="hero-body">
      <div class="container has-text-centered">
        <h2 class="title">Check out recent surveys</h2>
      </div>
    </div>
  </section>
  <section class="section">
    <div class="container">
      <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>
    </div>
  </section>
</div>
</template>

Guarde los archivos no guardados en el proyecto y actualice su navegador, que ahora debería aparecer como se muestra a continuación:

Como puede ver en la captura de pantalla, se muestran dos tarjetas de encuesta Bulma. Estas dos encuestas se asignan a la matriz de objetos de encuesta que estaban en mi función de datos de mi Homecomponente, que introduje en mi HTML usando la directiva v-for.

Eche un vistazo nuevamente a la subsección a continuación del código de la plantilla original, que representa una encuesta. Todo este elemento y sus elementos secundarios se repiten una vez para cada encuesta de la surveysmatriz. Básicamente, los datos impulsan la generación de HTML.

La parte clave de v-bind: es agregar un atributo llamado keyigual a la identificación de la encuesta a cada uno divcon la clase “tarjeta”. Vue usa estas claves para realizar un seguimiento explícito de cada nodo que se crea en el DOM, lo que ayuda en la contabilidad y el rendimiento. Se recomienda establecer siempre una clave única para el elemento más externo que se utiliza junto con una directiva v-for.

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

La directiva v-for usa una sintaxis de item in itemswhere itemses un iterable, como una matriz o las propiedades de un objeto, y itemes un alias para cada elemento del iterable. Sin embargo, existen variaciones de esta sintaxis, lo que permite una mayor flexibilidad y control.

Por ejemplo, digamos que tenía una matriz de letras var letters = ['a', 'd', 'a', 'm']que quería usar para impulsar la creación de una lista desordenada de HTML ole regular que muestra cada letra y su índice correspondiente. Bueno, eso se podría hacer con esta variación de v-for:

  <ul>
    <li v-for="(letter, i) in letters" v-bind:key="i">
      Index position {{ i }} has letter {{ letter }}
    </li>
  </ul>

Dando como resultado el siguiente resultado:

• Index position 0 has letter a
• Index position 1 has letter d
• Index position 2 has letter a
• Index position 3 has letter m

Para iterar sobre las propiedades de un objeto, la sintaxis es bastante similar. Dado un objeto como var person = { name: 'adam', occupation: 'software developer', residence: 'lincoln, nebraska' }, iterar con una directiva v-for se vería así:

  <ul>
    <li v-for="(value, key) in person" v-bind:key=”key”>
      key -> {{ key }}, value -> {{ value }}
    </li>
  </ul>
• key -> name, value -> adam
• key -> occupation, value -> software developer
• key -> residence, value -> lincoln, nebraska

Burlarse de una solicitud de encuestas AJAX

Tengo mi primer componente de interfaz de usuario funcional que muestra una colección de encuestas, pero al final la aplicación real necesitará obtener datos de la encuesta de nuestra API REST. Para hacer esto un poco más realista, me gustaría simular las funciones de una solicitud AJAX para alimentar las Homeencuestas de componentes.

En el directorio src crea una nueva carpeta llamada “api” y luego agrega un script llamado index.js dentro de ella. Aquí es donde me burlaré de mis funciones AJAX. En este nuevo archivo, corte y pegue la surveysmatriz del componente Home.vue como una constante global.

// api/index.js

const surveys = [{
  id: 1,
  name: 'Dogs',
  created_at: new Date(2018, 1, 1),
  questions: [{
    id: 1,
    text: 'What is your favorite dog?',
    choices: [
      { id: 1, text: 'Beagle', selected: 0 },
      { id: 2, text: 'Labrador', selected: 0 },
      { id: 3, text: 'Rottweiler', selected: 0 }]
  }, {
    id: 2,
    text: 'What is your second favorite dog?',
    choices: [
      { id: 5, text: 'Beagle', selected: 0 },
      { id: 6, text: 'Labrador', selected: 0 },
      { id: 7, text: 'Rottweiler', selected: 0 }]
  }]
}, {
  id: 2,
  name: 'Cars',
  created_at: new Date(2018, 1, 3),
  questions: [{
    id: 5,
    text: 'What is your favorite car?',
    choices: [
      { id: 17, text: 'Corvette', selected: 0 },
      { id: 18, text: 'Mustang', selected: 0 },
      { id: 19, text: 'Camaro', selected: 0 }]
  }, {
    id: 6,
    text: 'What is your second favorite car?',
    choices: [
      { id: 21, text: 'Corvette', selected: 0 },
      { id: 22, text: 'Mustang', selected: 0 },
      { id: 23, text: 'Camaro', selected: 0 }]
  }]
}]

Debajo de esta matriz de encuestas, cree una función llamada fetchSurveysque devuelve una promesa con la matriz de encuestas después de esperar 300 milisegundos (para simular el retraso de la API). La función deberá exportarse para que se pueda acceder a ella desde el Homecomponente.

export function fetchSurveys() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(surveys)
    }, 300)
  })
}

De vuelta en la función de datos del Homecomponente, inicialice la surveyspropiedad en una matriz vacía e importe la fetchSurveysfunción dentro de la sección del script.

<script>
import { fetchSurvey } from '@/api'
export default {
 data() {
    return {
      surveys: []
    }
  }
}
</script>

Los componentes de Vue tienen una serie de etapas definidas del ciclo de vida que son significativas para el desarrollador cuando hace varias cosas, como extraer datos mediante una solicitud AJAX. Para introducir datos de encuestas en el Homecomponente, necesitaré conectarme a una de las etapas del ciclo de vida de Vue, específicamente la beforeMountetapa. Hay varias otras etapas que son útiles para muchas más cosas además de las solicitudes AJAX, pero me remitiré a los documentos oficiales de Vue.js para obtener una explicación detallada.

La beforeMountetapa del ciclo de vida funciona bien para la llamada a la API porque se ejecuta justo antes de que comience el montaje de nuestro componente, y justo antes de que renderse llame a nuestro componente. Esto le da tiempo para recuperar los datos antes de mostrarlos al usuario.

Para aprovechar la beforeMountetapa del Homecomponente, todo lo que necesito hacer es agregarlo como un nuevo método al objeto Vue del componente. Dentro de esta función, realizaré una llamada a mi fetchSurveysfunción y asignaré las encuestas devueltas a la datapropiedad de encuestas .

<script>
import { fetchSurveys } from '@/api'
export default {
  data() {
    return {
      surveys: []
    }
  },
  beforeMount() {
    fetchSurveys().then(response => {
      this.surveys = response
    })
  }
}
</script>

Guardar todos los archivos en el proyecto y actualizar el navegador ahora me da la misma página de inicio que vimos anteriormente, pero ahora con una llamada AJAX simulada.

 

Conclusión

Esta publicación ha cubierto los conceptos básicos de la configuración de una aplicación Vue.js SPA con vue-cli usando la plantilla de paquete web. Además de la configuración del proyecto, cubrí cómo usar datos en forma de iterable para generar dinámicamente contenido de IU utilizando la poderosa directiva v-for Vue.js. Para el último tema principal, toqué las etapas del ciclo de vida de los componentes y cómo la beforeMountetapa puede ser útil para cargar datos en un componente con una solicitud AJAX simulada.

En la próxima publicación, cubriré cómo usar la extensión vue-router para pasar de una página a otra, dando a nuestra aplicación un concepto de flujo de trabajo. El código de este tutorial se puede encontrar en mi cuenta de GitHub, que contiene una rama para cada publicación. Gracias por leer y no dude en comentar o criticar a continuación.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad