Vue¶
CLI¶
It's succeeded by Vite.
in node_modules/.bin/vue-cli-service
run with npx vue-cli-service
init¶
Install Node.js¶
See NodeJs
Create vue project¶
With vue-cli-service¶
With Vite¶
In your project root, run
If there's an error, try update node to the latest version, open a new shell and run again. See NodeJs.
import¶
@ = /src
It's defined in vue.config.js or vite.config.js
e.g.
// they are the same
import Students from '@/components/Students.vue'
import Students from '/src/components/Students.vue'
environmental variables¶
https://vitejs.dev/guide/env-and-mode.html
It will use .env. All keys starting with VITE_ can be accessed with import.meta.env.<env_key>.
e.g.
Pinia¶
State management tool for Vue, successor of Vuex.
Example
https://codesandbox.io/s/pinia-vue-3-axios-interceptor-6jf11?file=/src/main.js
Init¶
Install pinia.
Add app.use(pinia) in main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia()
app.use(router)
app.use(pinia)
app.mount('#app')
Create a store¶
In src/stores/useStore.js
import { defineStore } from 'pinia'
export const useStore = defineStore('<id>', {
  state: () => {
    return {
      counter: 0,
      name: 'Eduardo',
      isAdmin: true,
    }
  },
})
Use your store¶
To access & modify the store in a random component
First import it.
Then you can directly use it.
  methods: {
    test() {
      // useStore().counter++
      const haha = useStore();
      haha.counter++;
      console.log(haha.counter);
    }
  }
Or you can declare it with
or
Now you can access it with this.haha like a normal component data.
Watch your store¶
<script>
export default {
  computed: {
    timeRange(){
      return this.globe.timeRange;
    },
  },
  watch: {
    timeRange(newVal, oldVal) {
      // do something
    }
  },
}
</script>
You can also use is directly as key
routing¶
vue-router doc
a nice tutorial
Install vue-router
Define routes in src/main.js
import { createApp } from 'vue'
import App from '@/App.vue'
// import router from '@/router'
import { createRouter, createWebHistory } from 'vue-router'
import Students from '@/views/Students_blade.vue'
import Home from '@/views/Home_blade.vue'
const routes = [
  { path: '/', component: Home},
  { path: '/students', component: Students },
  { path: "/:pathMatch(.*)", name: "not-found", component: Invalid },
];
const router = createRouter({
  history: createWebHistory(),
  // history: createWebHashHistory(),
  routes,
});
// export default router;
// createApp(App).use(router).mount('#app')
const app = createApp(App)
app.use(router)
app.mount('#app')
You can put the routes in /src/router.js and import it to make it cleaner.
To show the html of the routing target
You can put it in index.html or App.vue. Without this, the routing you've defined will do exactly nothing.
base url¶
Give base url in createWebHistory() (or createWebHashHistory(). 
If you use vite, then it's
https://github.com/vitejs/vite/issues/2114#issuecomment-782727527
fallback route¶
Link to route¶
To link to this route,
Do this. It will match to the route with the same name and pass the params.
<router-link :to="{name: 'student', params: {id: student.student_id}}"> {{ student.student_name }}</router-link>
history mode¶
It defines how your url will look like. With HTML5 mode, url will look like domain/path. With hash mode, url will look like domain/#/path. See the comparison below.
- HTML5- command: createWebHistory
- pros: url looks natural
- cons: can't be directly accessed (because you don't actually have a file in that route)
 
- command: 
- Hash- command: createWebHashHistory
- pros: can be directly accessed
- cons: url is different from the norm
 
- command: 
There's also a memory mode, which doesn't change the url at all.
parameters¶
$route.params.<key> to access url variables
$route.name to access the route name
e.g.
For { path: '/std/:id', name: "student", component: Data },
$route.params.id = the id
$route.name = "student"
export default¶
data¶
Define values
computed¶
define values that need to be computed
will automatically be recomputed
methods¶
Define functions
mounted¶
execute when first load
directive¶
v-bind¶
To access data value in html tag, shorthand to :
v-on¶
Event listener, shorthand to @.
v-model¶
<input v-model:"haha"> will automatically make haha = input value
v-if¶
v-for¶
<div>
<ul>
  <li v-for="student in students">
    {{ student['student_id'] }} {{ student['student_name'] }}
  </li>
</ul>
</div>
refresh¶
When text is changed, this element will be refreshed.
Can also watch multiple variables.
You can manipulate it and put it on <router-view /> to refresh the page, or on whatever component to refresh that component, for example.
<script setup>
import Students from '@/components/Students.vue'
import Attendance from '../components/Attendance.vue';
</script>
<script>
export default {
  data() {
    return {
      update: 0,
    }
  },
  methods: {
    refresh() {
      this.update++;
    }
  }
}
</script>
<template>
<h1>Current State of the Classroom</h1>
<button class='btn' id="refresh" @click="refresh()">refresh</button>
<h2>Attendance</h2>
<Attendance :key="update"/>
<h2>Specific Students</h2>
<Students :key="update"/>
</template>
https://stackoverflow.com/a/54367510/15493213
run locally¶
dev¶
With Vite
run with express¶
var express = require('express');
var path = require('path');
var serveStatic = require('serve-static');
app = express();
app.use(serveStatic(__dirname + "/dist"));
var port = process.env.PORT || 7070;
var hostname = '127.0.0.1';
app.listen(port, hostname, () => {
   console.log(`Server running at http://${hostname}:${port}/`);
 });
https://stackoverflow.com/a/53945050/15493213
build for production¶
It will produce static files in dist/. To host your vue app, push these static files to whatever hosting option you like.
To disable file name hashing, add this in vite.config.js in defineConfig
build: {
  rollupOptions: {
    output: {
      entryFileNames: `assets/[name].js`,
      chunkFileNames: `assets/[name].js`,
      assetFileNames: `assets/[name].[ext]`
    }
  }
}
or if you use vue-cli, see https://cli.vuejs.org/config/#filenamehashing.
With Flask¶
Modify Flask's template folder & static folder to vue's.
IDE¶
VsCode with Volar extension
sample¶
<script>
let id = 3;
let sample = {};
for(let i=0; i<id; i++){
  sample[i] = "sample " + i;
}
export default {
  data() {
    return {
      newTodo: '',
      todos: sample,
    }
  },
  methods: {
    addTodo() {
      this.todos[id++] = this.newTodo
    },
    removeTodo(id) {
      console.log(id)
      delete(this.todos[id])
    }
  }
}
</script>
<template>
  <form @submit.prevent="addTodo">
    <input v-model="newTodo">
    <button>Add Todo</button>    
  </form>
  <ul>
    <li v-for="(text, id) in todos" :key="id">
      {{text}} {{id}}
      <button @click="removeTodo(id)">X</button>
    </li>
  </ul>
</template>
Troubleshooting¶
yarn dependency problem¶
ignore engines temporarily
or
https://github.com/vuejs/vue-cli/issues/7116
Uncaught TypeError: store.$id is undefined¶
or Uncaught TypeError: Cannot read properties of undefined (reading 'startsWith')
maybe you didn't give your pinia store a id