VUE3 integrates TS and Vue router

Posted by BZero on Mon, 07 Mar 2022 07:50:37 +0100

preface

be careful

VUE3 is not recommended at this stage for the following reasons:

  1. No longer compatible with IE11
  2. The ecology of the three parties is not perfect
  3. The relevant documents are not perfect, and the problems encountered are relatively difficult to solve

However, the matching experience of VUE3 and TS is relatively good.

VUE3 official website

When Vue 3.2 was released, Youda already provided the best practice solution on Weibo:

< script setup > + TS + volatile = really fragrant

Volar is a plug-in of VS Code. Its biggest function is to solve the TS prompt problem of template.

be careful

When using it, you should first remove Vetur to avoid conflict.

< script setup > is a compile time syntax for using composite API s in single file components (SFC). Compared with ordinary script syntax, it has more advantages:

  • Less template content, more concise code.
  • Can declare props and emit events using pure Typescript.
  • Better runtime performance (its template will be compiled into rendering functions with the same scope without any intermediate agents).
  • Better IDE type inference performance (reducing the work of the language server to extract types from the code).

See official documents for details Single file component

Create project

Vite

Create project

Vite Is a web development and construction tool. Due to its native ES module import mode, it can realize lightning cold server startup.

You can use Vite to quickly build Vue projects by running the following commands in the terminal.

View npm version

npm -v

Create project

# npm 6.x
npm init vite@latest vue3_demo01 --template vue

cd vue3_demo01
npm install
npm run dev

be careful:

# npm 7 +, additional double dashes are required
npm init vite@latest vue3_demo01 -- --template vue

If an error is reported

Error: Cannot find module 'worker_threads'

as a result of:

Vite requires node JS version > = 12.0.0.

Switch Node version

View my own Node edition

node -v

Therefore, you can upgrade the Node version. Here, nvm is used to manage the Node version

nvm can be downloaded and installed through the following connection.

http://nvm.uihtm.com/

Set mirror address

Under the installation path of nvm, find settings txt

After addition, the contents are as follows:

root: D:\Tools\nvm
path: D:\Tools\nodejs
node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/

Or execute

nvm node_mirror https://npm.taobao.org/mirrors/node/
nvm npm_mirror https://npm.taobao.org/mirrors/npm/

Switch version

# View available versions
nvm list

# Latest version 12 installation
nvm install 12.22.6

# Switch to 12.22.6
nvm use 12.22.6

node -v

Add TS / Vue router, etc

Install typescript, vue-router@next , axios, eslint plugin Vue, less and other related plug-ins

npm install axios
npm install vue-router@next
npm install typescript -D
npm install less -D

vite.config.ts

vite.config.js renamed vite config. ts

import { UserConfig } from 'vite'
const path = require('path')
import vue from '@vitejs/plugin-vue'

const config: UserConfig = {
  plugins: [vue()],
  optimizeDeps: {
    include: [ 'axios' ]
  },
  resolve: {
    alias: {
    '/@': path.resolve( __dirname, './src' )
    },
  },
}

export default config

router

Create a new router folder under src, and create index ts

import { createRouter, createWebHashHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('/@/views/Home.vue')
  }
]

export default createRouter({
  history: createWebHashHistory(),
  routes
})

views

Add views folder under src

Add home vue

<script setup></script>

<template>
  <div class="div1">
    <div class="div2">Coder said</div>
  </div>
</template>

<style scoped lang="less">
.div1 {
  .div2 {
    font-size: 20px;
  }
}
</style>

App. Under src Add < router View > < / router View > to Vue

<script setup>
import HelloWorld from "./components/HelloWorld.vue";
</script>

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + Vite" />

  <router-view></router-view>
</template>

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

ts configuration

Create a new tsconfig. In the project root directory JSON write related configuration

{
  "compilerOptions": {
    "allowJs": true,
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": ["vite/client"],
    "paths": {
      "/@/*": ["src/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx",
    "vite.config.ts"
  ],
  "exclude": ["node_modules"]
}

Create a new types folder under the src directory, where you need to configure the type of ts

shims-vue.d.ts

declare module '*.vue' {}

images.d.ts

declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'

main.ts

Main under src JS to main ts

import { createApp } from 'vue'
import router from '/@/router'

import App from '/@/App.vue'

const app = createApp(App)
app.use(router)
app.mount('#app')

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

Mainly

<script type="module" src="/src/main.js"></script>

Change to

<script type="module" src="/src/main.ts"></script>

VUE3 knowledge

setup

vue3 integrates all APIs with setup function; It is executed only once and before the life cycle function, so the current instance this cannot be obtained in the setup function, and the method defined in vue2 writing method cannot be called with this

It will accept two parameters: props and context

// Context to context properties of props component 
setup(props, context) {
  return {
    // Data and methods to bind
  }
}

props props in the setup function is responsive. When a new prop is passed in, it will be updated However, because props is responsive, ES6 deconstruction cannot be used because it will eliminate the responsiveness of props

If you need to deconstruct prop, you can do this safely by using toRefs in the setup function

import { toRefs } from 'vue'

setup(props) {
  const { title } = toRefs(props)
  console.log(title.value)
}

context context exposes the properties of three components: {attrs, slots, emit} It is an ordinary JavaScript object, not responsive, which means you can safely use ES6 to deconstruct the context

The setup method is equivalent to the following

<script setup>

</script>

life cycle

Access the component's lifecycle hook by adding on before the lifecycle hook

Because setup runs around the beforeCreate and created lifecycle hooks, there is no need to explicitly define them In other words, any code written in these two hooks should be written directly in the setup function

setup() {
  onMounted(() => {
    console.log('Component mount')
  })

  onUnmounted(() => {
    console.log('Component Uninstallation ')
  })

  onUpdated(() => {
    console.log('Component update')
  })

  onBeforeUpdate(() => {
    console.log('Component will be updated')
  })

  onActivated(() => {
    console.log('keepAlive Component activation')
  })

  onDeactivated(() => {
    console.log('keepAlive Component inactive')
  })

  return {}
}

ref,reactive

ref can wrap a common value into responsive data, which is limited to simple values. Internally, the value is wrapped into an object and processed through defineProperty When passing the value, value and setting value of ref package, you need to pass Value to set You can use ref to get the reference of the component instead of this$ Writing method of refs

reactive handles complex data responsively. Its return value is a proxy object. When it is returned in the setup function, you can use toRefs to structure the proxy object, which is convenient to use in the template

Use the following:

<template>
  <div>
    <div>
      <ul v-for="ele in eleList" :key="ele.id">
        <li>{{ ele.name }}</li>
      </ul>
      <button @click="addEle">add to</button>
    </div>
    <div>
      <ul v-for="ele in todoList" :key="ele.id">
        <li>{{ ele.name }}</li>
      </ul>
      <button @click="addTodo">add to</button>
    </div>
  </div>
</template>

<script>
import { ref, reactive, toRefs } from 'vue'

export default {
  setup() {
    // ref
    const eleList = ref([])
    function addEle() {
      let len = eleList.value.length
      eleList.value.push({
        id: len,
        name: 'ref Self increasing' + len
      })
    }

    // reactive
    const dataObj = reactive({
      todoList: []
    })
    function addTodo() {
      let len = dataObj.todoList.length
      dataObj.todoList.push({
        id: len,
        name: 'reactive Self increasing' + len
      })
    }

    return {
      eleList,
      addEle,
      addTodo,
      ...toRefs(dataObj)
    }
  }
}
</script>

computed,watch

// computed
let sum = computed(
    () => dataObj.todoList.length + eleList.value.length
)
console.log('setup quote computed want.value: ' + sum.value)

// watch
watch(
  eleList,
  (curVal, oldVal) => {
    console.log('monitor:', curVal, oldVal)
  },
  {
    deep: true
  }
)

watchEffect

The responsive data referenced in the function is tracked responsively. When the responsive data changes, the function is re executed

const count = ref(0)
// When the value of count is modified, a callback is executed
const stop = watchEffect(() => console.log(count.value))

// Stop listening
stop()

You can also stop listening. watchEffect returns a function that can stop listening after execution

Same as vue2:

const unwatch = this.$watch('say', curVal => {})

// Stop listening
unwatch()

useRoute,useRouter

import {useRoute, useRouter} from 'vue-router'

const route = useRoute() // Equivalent to this in vue2$ route
const router = useRouter() // Equivalent to this in vue2$ router

// Route is used to obtain the current route data
// router is used for route jump

vuex

When using useStore to obtain the value of the store object from vuex, it should be noted that calculated must be used for packaging, so that the response can be made in the page after the status in vuex is modified

import {useStore} from 'vuex'

setup(){
  const store = useStore() // Equivalent to this in vue2$ store
  store.dispatch() // dispatch asynchronous tasks through store object
  store.commit() // commit modify store data
    
  let category = computed(() => store.state.home.currentCagegory
  return { category }
}

Vue Cli

vue ui

Vue3 can be selected for VUE version during installation

Available UI frameworks

https://next.antdv.com/docs/vue/getting-started-cn