Vite2 + Vue3 + Typescript 入门级教程

人生代码

共 19032字,需浏览 39分钟

 · 2021-03-17

Vite2 + Vue3 + Typescript 入门级教程

新建项目

创建项目目录 todoList

我们来到 Vite2 的官网,网址如下:

https://vitejs.dev/guide/#scaffolding-your-first-vite-project

Vite2 内置了很多中模板:

vanilla
vue
vue-ts
react
react-ts
preact
preact-ts
lit-element
lit-element-ts

今天我们选择 vue 这个模板来创建项目:

# npm 6.x
npm init @vitejs/app my-vue-app --template vue

# npm 7+, extra double-dash is needed:
npm init @vitejs/app my-vue-app -- --template vue

# yarn
yarn create @vitejs/app my-vue-app --template vue

安装 typescript

yarn add typescript

接着使用以下命令来初始化 ts 配置:

npx tsc --init

接着我们将 main.js 修改为 main.ts

接着我们将 index.html 中的:

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

改成如下:

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

这个时候我们发现 App.vue 会有警告:


这是怎么回事呢?

/**
 * shim.d.ts的作用
 * 为了 typescript 做的适配定义文件,因为.vue 文件不是一个常规的文件类型,ts 是不能理解 vue 文件是干嘛的,
 * 加这一段是是告诉 ts,vue 文件是这种类型的。
 * 可以把这一段删除,会发现 import 的所有 vue 类型的文件都会报错。
 */

所以我们需要在项目根目录创建 shim.d.ts 来定义 .vue 模块:

declare module "*.vue" {
    import { Component } from "vue";
    const component: Component;
    export default component;
}

这个时候 App.vue 就不会报错了。

安装 vue-router vuex

yarn add vue-router@4.x vuex@4.x

src 目录新建 router/index.ts

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

// 在 Vue-router新版本中,需要使用createRouter来创建路由
export default createRouter({
  // 指定路由的模式,此处使用的是hash模式
  history: createWebHashHistory(),
  // 路由地址
  routes: []
})

接着在 src 中新建 store/index.ts:

import { createStore } from 'vuex'
// ts 中接口数据
interface State {
  userName: string,
  taskList: any[]
}

let state: State = {
    userName: "小仙女",
    taskList: []
}

export default createStore({
    state,
});

安装 sass sass-loader

yarn add sass sass-loader -D

然后在根目录下新建 index.scss

#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}

然后在 main.ts 引入代码:

import { createApp } from 'vue'
import App from './App.vue'
import './index.scss'
import router from './router/index'
import vuex from './store/index'

const  app = createApp(App)

app.use(router)
app.use(vuex)
app.mount('#app')

配置路由

首先我们需要在 src 下新建 views/home.vue

<template>
  <div class="home">
    <!-- input输入list内容 -->
    <div>
      <input
        @keyup.enter="addTask"
        class="input"
        type="text"
        v-model="inputValue"
        placeholder="请输入"
      />

    </div>
    <!-- todoList内容展示和删除 -->
    <ul class="ul">
      <li class="item" v-for="(item, index) in taskList" :key="index">
        <p
          @click="updateStatus(index, !item.isfinished)"
          class="content"
          :class="item.isfinished ? 'active' : ''"
        >
{{item.lable}}</p>
        <div class="item-delete" @click="deleteTask(index)">X</div>
      </li>
      <li v-if="taskList.length === 0" class="item-none">暂无数据</li>
    </ul>
  </div>
</template>

<style scoped lang='scss'>
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
ul,
li {
  list-style: none;
  text-align: left;
}
.home {
  max-width: 400px;
  margin: 0 auto;
  .input {
    width: 100%;
    height: 40px;
    border-radius: 5px;
    outline-style: none;
    border: 2px solid #999;
    padding: 5px 10px;
  }
  .ul {
    margin-top: 10px;
  }
  .item {
    height: 40px;
    line-height: 40px;
    padding-bottom: 5px;
    border-bottom: 1px solid #dcdfe6;
    color: #333333;
  }
  .item-none {
    height: 40px;
    line-height: 40px;
    padding-bottom: 5px;
    color: #333333;
    text-align: center;
  }
  .content {
    float: left;
    height: 40px;
    line-height: 40px;
    cursor: pointer;
  }
  p.active {
    text-decoration:line-through; 
    color: #999999;
  }
  .item-delete {
    float: right;
    width: 25px;
    text-align: center;
    cursor: pointer;
  }
}
</style>

src 新建 views/about.vue

<template>
    <div id="about" class="about-wrap">
        about
    </div>
</template>

<script>
export default {
    name'about'
}
</script>

然后在 router/index.ts 配置路由:

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

// 在 Vue-router新版本中,需要使用createRouter来创建路由
export default createRouter({
  // 指定路由的模式,此处使用的是hash模式
  history: createWebHashHistory(),
  // 路由地址
  routes: [
      {
          path'/',
          name'home',
          component() => import('../views/home.vue')
      },
      {
          path'/about',
          name'about',
          component() => import('../views/about.vue')
      }
  ]
})

在配置路由的这个过程你可能会碰到这个问题:

解决的方式如下:

tsconfig.json 下来配置:

"lib": ["es2015"]

这个时候,报错就解除了。

然后在 App.vue

<template>
  <div id="app-wrap">
    <div class="nav" id="nav">
      <router-link to='/'>todoList</router-link>
      <router-link to='/about'>about</router-link>
    </div>
    <router-view></router-view>
  </div>
</template>

<script lang="ts">

export default {
  name'App',
  components: {}
}

// This starter template is using Vue 3 experimental <script setup> SFCs
// Check out https://github.com/vuejs/rfcs/blob/script-setup-2/active-rfcs/0000-script-setup.md
</script>

添加任务

我们需要一个 store 仓库来保存任务列表,每个列表项有一个状态标识。

store/index.ts

import { createStore } from 'vuex'
// 定义一个接口数据,用来限定 state 里面有两个属性
// 一个是 userName
// 一个是 taskList
interface State {
  userName: string,
  taskList: any[]
}

let state: State = {
    userName"小仙女",
    taskList: []
}

export default createStore({
    state
})

页面上我们需要输入框输入内容之后,回车触发向仓库添加数据,在 views/home.vue 添加如下代码:

<script lang="ts">
import { ref, computed, defineComponent } from 'vue'
import { useStore } from 'vuex'
export default defineComponent({
  name"home",
  setup() {
      // 使用 hook 的方式,拿到 store 仓库
      const store = useStore()
      // 通过 get 的方式链接 store.state.taskList
      const taskList = computed(() => store.state.taskList)
      // 绑定输入框
      let inputValue = ref("")
      // 向数据仓库提交一个 createTask 方法修改 taskList 数组
      // 修改之后将 inputValue 制空
      const addTask = () => {
          store.commit('createTask', {
              lable: inputValue.value,
              isfinishedfalse  
          })

          inputValue.value = ""
      }

      return {
          taskList,
          inputValue,
          addTask,
      }
  }
});
</script>

接下来我们需要在 store/index.ts 给数据仓库定义 mutations,用来接收外部提交的执行的方法:

export default createStore({
    state,
    mutations: {
        createTask(state: any, newTask: any) {
            state.taskList.push(newTask)
        },
    }
});

更新任务

当我们点击任务列表项时,需要重新设置列表项的状态值,所以我们需要在 views/home.vue 定义一个更新状态的方法,这个方法只需要传递列表项的下标以及状态值:

<script lang="ts">
import { ref, computed, defineComponent } from 'vue'
import { useStore } from 'vuex'
export default defineComponent({
  name"home",
  setup() {
      const store = useStore()
      const taskList = computed(() => store.state.taskList)
      let inputValue = ref("")

      const addTask = () => {
          store.commit('createTask', {
              lable: inputValue.value,
              isfinishedfalse  
          })

          inputValue.value = ""
      }

      const updateStatus = (index, status) => {
          store.commit('updateStatus', {
              index,
              status
          })
      }

      return {
          taskList,
          inputValue,
          addTask,
          updateStatus,
      }
  }
});
</script>

然后我们需要在 store/index.ts 添加更新任务的方法:

export default createStore({
    state,
    mutations: {
        createTask(state: any, newTask: any) {
            state.taskList.push(newTask)
        },
        // 接收 state, payload
        updateStatus(state: any, payload: any) {
            // 解构 index, status
            const {index, status} = payload
            // 修改列表项的状态
            state.taskList[index].isfinished = status
        },
    }
});

删除任务

当我们点击列表项的删除按钮的时候,需要向仓库提交方法删除列表项,所以我们需要在 views/home.vue 下添加删除任务的方法,只需要将下标传递过去就行:

<script lang="ts">
import { ref, computed, defineComponent } from 'vue'
import { useStore } from 'vuex'
export default defineComponent({
  name"home",
  setup() {
      const store = useStore()
      const taskList = computed(() => store.state.taskList)
      let inputValue = ref("")

      const addTask = () => {
          store.commit('createTask', {
              lable: inputValue.value,
              isfinishedfalse  
          })

          inputValue.value = ""
      }

      const updateStatus = (index, status) => {
          store.commit('updateStatus', {
              index,
              status
          })
      }

      const deleteTask = (index) => {
          store.commit('deleteTask', {
              index
          })
      }

      return {
          taskList,
          inputValue,
          addTask,
          updateStatus,
          deleteTask
      }
  }
});
</script>

然后在 store/index.ts 新增删除方法:

export default createStore({
    state,
    mutations: {
        createTask(state: any, newTask: any) {
            state.taskList.push(newTask)
        },
        updateStatus(state: any, payload: any) {
            const {index, status} = payload
            state.taskList[index].isfinished = status
        },
        // 删除任务方法
        deleteTask(state, payload: any) {
            // 只需要解构 index
            const {index} = payload
            // 将对应的数据删除即可
            state.taskList.splice(index, 1)
        }
    }
});

到此为止,我们的 todoList 已经圆满结束了,我们来运行下,看看效果吧。



浏览 72
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报