前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >VUE3集成TS和vue-router

VUE3集成TS和vue-router

作者头像
码客说
发布2022-03-07 14:26:54
1.2K0
发布2022-03-07 14:26:54
举报
文章被收录于专栏:码客

前言

注意

现阶段并不建议使用VUE3,原因如下:

  1. 不再兼容IE11
  2. 三方的生态并不完善
  3. 相关文档并不完善,遇到问题相对不太好解决

但是VUE3和TS搭配体验相对较好。

VUE3 官网

尤大在 Vue 3.2 发布的时候已经在微博给出了最佳实践的解决方案:

<script setup> + TS + Volar = 真香

Volar 是个 VS Code 的插件,其最大的作用就是解决了 template 的 TS 提示问题。

注意

使用它时,要先移除 Vetur,以避免造成冲突。

<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 script 语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码。
  • 能够使用纯 Typescript 声明 props 和发出事件。
  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。
  • 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。

详见官方文档 单文件组件

创建项目

Vite

创建项目

Vite 是一个 web 开发构建工具,由于其原生 ES 模块导入方式,可以实现闪电般的冷服务器启动。

通过在终端中运行以下命令,可以使用 Vite 快速构建 Vue 项目。

查看npm版本

代码语言:javascript
复制
npm -v

创建项目

代码语言:javascript
复制
# npm 6.x
npm init vite@latest vue3_demo01 --template vue

cd vue3_demo01
npm install
npm run dev

注意:

代码语言:javascript
复制
# npm 7+,需要加上额外的双短横线
npm init vite@latest vue3_demo01 -- --template vue

如果报错

Error: Cannot find module ‘worker_threads’

原因是:

Vite 需要 Node.js 版本 >= 12.0.0。

切换Node版本

查看我自己的Node版本

代码语言:javascript
复制
node -v

所以升级Node版本即可,这里使用nvm管理Node版本

nvm可以通过下面的连接下载安装即可。

http://nvm.uihtm.com/

设置镜像地址

在 nvm 的安装路径下,找到 settings.txt

添加后内容如下:

代码语言:javascript
复制
root: D:\Tools\nvm
path: D:\Tools\nodejs
node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/

或者执行

代码语言:javascript
复制
nvm node_mirror https://npm.taobao.org/mirrors/node/
nvm npm_mirror https://npm.taobao.org/mirrors/npm/

切换版本

代码语言:javascript
复制
# 查看可用版本
nvm list

# 安装最新的12版
nvm install 12.22.6

# 切换到12.22.6
nvm use 12.22.6

node -v

添加TS/vue-router等

安装 typescript、vue-router@next、axios、eslint-plugin-vue、less等相关插件

代码语言:javascript
复制
npm install axios
npm install vue-router@next
npm install typescript -D
npm install less -D

vite.config.ts

vite.config.js重命名为vite.config.ts

代码语言:javascript
复制
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

在 src 下新建 router 文件夹,并在文件夹内创建 index.ts

代码语言:javascript
复制
import { createRouter, createWebHashHistory } from 'vue-router'

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

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

views

src下添加views文件夹

添加Home.vue

代码语言:javascript
复制
<script setup></script>

<template>
  <div class="div1">
    <div class="div2">码客说</div>
  </div>
</template>

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

src下的App.vue中添加<router-view></router-view>

代码语言:javascript
复制
<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 配置

项目根目录下新建 tsconfig.json 写入相关配置

代码语言:javascript
复制
{
  "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"]
}

src 目录下新建 types 文件夹,里面需要配置 ts 的类型

shims-vue.d.ts

代码语言:javascript
复制
declare module '*.vue' {}

images.d.ts

代码语言:javascript
复制
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'

main.ts

src下的main.js重命名为main.ts

代码语言:javascript
复制
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

代码语言:javascript
复制
<!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>

主要是

代码语言:javascript
复制
<script type="module" src="/src/main.js"></script>

修改为

代码语言:javascript
复制
<script type="module" src="/src/main.ts"></script>

VUE3 知识

setup

vue3 中用 setup 函数整合了所有的 api;只执行一次,在生命周期函数前执行,所以在 setup 函数中拿不到当前实例 this,不能用 this 来调用 vue2 写法中定义的方法

它将接受两个参数:props、context

代码语言:javascript
复制
// props - 组件接受到的属性 context - 上下文 
setup(props, context) {
  return {
    // 要绑定的数据和方法
  }
}

props setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新 但是,因为 props 是响应式的,不能使用 ES6 解构,因为它会消除 prop 的响应性

如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成此操作

代码语言:javascript
复制
import { toRefs } from 'vue'

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

context context 暴露三个组件的 property:{ attrs, slots, emit } 它是一个普通的 JavaScript 对象,不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构

setup方法和以下是等效的

代码语言:javascript
复制
<script setup>

</script>

生命周期

通过在生命周期钩子前面加上on来访问组件的生命周期钩子

因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们 换句话说,在这两个钩子中编写的任何代码都应该直接在 setup 函数中编写

代码语言:javascript
复制
setup() {
  onMounted(() => {
    console.log('组件挂载')
  })

  onUnmounted(() => {
    console.log('组件卸载')
  })

  onUpdated(() => {
    console.log('组件更新')
  })

  onBeforeUpdate(() => {
    console.log('组件将要更新')
  })

  onActivated(() => {
    console.log('keepAlive 组件 激活')
  })

  onDeactivated(() => {
    console.log('keepAlive 组件 非激活')
  })

  return {}
}

ref、reactive

ref 可以将某个普通值包装成响应式数据,仅限于简单值,内部是将值包装成对象,再通过 defineProperty 来处理的 通过 ref 包装的值,取值和设置值的时候,需用通过 .value来进行设置 可以用 ref 来获取组件的引用,替代 this.$refs 的写法

reactive 对复杂数据进行响应式处理,它的返回值是一个 proxy 对象,在 setup 函数中返回时,可以用 toRefs 对 proxy 对象进行结构,方便在 template 中使用

使用如下:

代码语言:javascript
复制
<template>
  <div>
    <div>
      <ul v-for="ele in eleList" :key="ele.id">
        <li>{{ ele.name }}</li>
      </ul>
      <button @click="addEle">添加</button>
    </div>
    <div>
      <ul v-for="ele in todoList" :key="ele.id">
        <li>{{ ele.name }}</li>
      </ul>
      <button @click="addTodo">添加</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 自增' + len
      })
    }

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

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

computed、watch

代码语言:javascript
复制
// computed
let sum = computed(
    () => dataObj.todoList.length + eleList.value.length
)
console.log('setup引用computed要.value:' + sum.value)

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

watchEffect

响应式地跟踪函数中引用的响应式数据,当响应式数据改变时,会重新执行函数

代码语言:javascript
复制
const count = ref(0)
// 当 count 的值被修改时,会执行回调
const stop = watchEffect(() => console.log(count.value))

// 停止监听
stop()

还可以停止监听,watchEffect 返回一个函数,执行后可以停止监听

与 vue2 一样:

代码语言:javascript
复制
const unwatch = this.$watch('say', curVal => {})

// 停止监听
unwatch()

useRoute、useRouter

代码语言:javascript
复制
import {useRoute, useRouter} from 'vue-router'

const route = useRoute() // 相当于 vue2 中的 this.$route
const router = useRouter() // 相当于 vue2 中的 this.$router

// route   用于获取当前路由数据
// router  用于路由跳转

vuex

使用 useStore 来获取 store 对象 从 vuex 中取值时,要注意必须使用 computed 进行包装,这样 vuex 中状态修改后才能在页面中响应

代码语言:javascript
复制
import {useStore} from 'vuex'

setup(){
  const store = useStore() // 相当于 vue2 中的 this.$store
  store.dispatch() // 通过 store 对象来 dispatch 派发异步任务
  store.commit() // commit 修改 store 数据
    
  let category = computed(() => store.state.home.currentCagegory
  return { category }
}

Vue Cli

代码语言:javascript
复制
vue ui

安装时VUE版本选择Vue3即可

可用UI框架

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 创建项目
  • Vite
    • 创建项目
      • 切换Node版本
        • 添加TS/vue-router等
          • vite.config.ts
          • router
          • views
          • ts 配置
          • main.ts
          • index.html
        • VUE3 知识
          • setup
          • 生命周期
          • ref、reactive
          • computed、watch
          • watchEffect
          • useRoute、useRouter
          • vuex
      • Vue Cli
      • 可用UI框架
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档