一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)

TypeScript

2020年了,身为前端的我们来说,要承认的一个事实就是typescript是越来越火了。
可以看看NPM官方的周下载量
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第1张图片
达到了1000+万次的周下载量
这个图可以告诉我们确实,将来的前端主流可能要向TypeScript偏移了,因为免不了的就是规范。

那么说到TypeScript,那么他到底是什么呢?他到底怎么去使用呢?
其实众所周知 javascript是一个弱类型语言,举一个最简单的比方我们在使用js声明一个变量时,是不需要去声明变量类型的

var a = 10 // 我声明了一个变量

有好处吗?当然有,省事
有坏处吗?当然有,类型不明显

那么TypeScript是什么呢?
其实就是用来规划js语言的,将js的写法用强类型的写法去写
我们可以看看typescript声明变量

var a:Number = 10 //我声明了一个Number类型的变量

其实并没有什么差别,就是我在变量后指定了它的类型
就是要告诉他我声明了一个number类型的变量

简单的了解了TypeScript之后,我们就可以直接去看一下怎么样使用typescript

在Vue中使用typeScript

首先我这边技术栈是使用了Vue,当然像React也是可以使用typescript的,而Angular规范语言就是ts,所以我们在这里就先来介绍在Vue中如何去使用ts

首先免不了的还是使用我们的VueCli来创建项目,而现在其实vue3也快出来了,当然大家也要抓紧时间去学习vue3呀。
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第2张图片
我们可以看到在我们使用

vue create ts

页面呈现效果,其实这个时候我们可以直接勾选typescript
我们也可以不勾选,在内部手动进行安装,在这里的话我们就先不进行勾选了,等项目创建完成之后我们可以进行手动安装ts

当项目创建完成之后
我们进入到项目当中
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第3张图片
这是我们的项目结构,我们这个时候可以使用

vue add @vue/typescript

将js+vue项目 转成 ts+vue项目
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第4张图片
这个时候会让我们选择,就一直Y就可以了
我们使用npm run serve启动项目之后
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第5张图片
呈现这个窗口也就成功了

项目呈现效果

一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第6张图片
其实也就是所谓的增删改查
那么上干货走起
其实我们的增删改查也没有用到后台的数据接口,只是说单纯的使用到了localstorage来进行一系列的增删改查

第一步

安装vuex

npm install vuex -S

在src下创建store/index.ts文件 注意是ts文件
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第7张图片
store/index.ts

import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex

Vue.use(Vuex) // 挂载vuex


const store = new Vuex.Store({
  state: {
    menuList: ''
  },
  mutations: {
  }
})
// 导出store,我们在main.ts中引入store
export default store

src/main.ts
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第8张图片

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

Vue.config.productionTip = false

new Vue({
  store, // 挂载store
  render: h => h(App)
}).$mount('#app')

第二步

我们新建一个类文件,专门用于存储一系列的类方法
我这边在src文件夹下新建了一个model文件专门用来存储
model/CurdMethods.ts

// 定义接口
interface All {
  isCate: number,
  id: number,
  title: string,
  content: string,
  [propName: string]: any
}

// 定义接口  接口是什么? 其实接口就是用来规范定义对象类型的 可以简单的将其理解为一个 String 只不过这个规则String是我们自己来定义的
interface IClass {
  MenuList:any // 表示任意类型  一个any走遍TypeScript  其实我们是不到万不得已不推荐使用的
  isCate:number
  id:number
  title:string
  content:string
  Read():object // 表示return一个对象
  Add(objCan:any):void // void 表示无返回值类型  函数后添加 :类型  表示return 的类型
  Edit(objCan:any):void
  Del(objCan:any):void
  smallTianCai?:string // 可以定义也可一部定义
  [propName: string]: any //接口任意属性
}

class CurdMethods implements IClass {
  // 所有文章列表
  MenuList!: any // !: 表示这个对象我们在初始时可以不给他赋值  只是单纯的声明,如果不加 ! 的话ts会给我们报错
  // 类别分类
  isCate !: number
  // id
  id!: number
  // 标题
  title !: string
  // 内容
  content !: string
  constructor(isCate: number = 0, id: number = -1, title: string = '', content: string = '') {
    this.id = id
    this.isCate = isCate
    this.title = title
    this.content = content
    // 实例化的时候就去执行获取数据
    this.MenuList = this.Read()
  }
  // 查询方法
  Read(): object {
    // 从localStorge中获取数据 :string | null 代表的意思是 这个Menu的值可以是字符串也可以是null  因为获取的数据可能是字符串也可能没有就是null
    let strData: string | null = localStorage.getItem('Menu')
    // 声明一个变量  指定类型在这里我们给其定义为一个any类型  值为 [ ]
    let Menu: any = []
    // 如果strData不是 null的话 就说明有数据  有数据我们就给null赋值
    if (strData != null) {
      // JSON.parse 转译为数组对象
      Menu = JSON.parse(strData)
    }
    // 将这个数组对象赋值给 this.MenuList
    this.MenuList = Menu
    // 我们将这个查出的数据  同样return 出去  以方便别的类方法中调用
    return Menu
  }
  // 增加方法
  Add(objCan:any): void {
    // 获取this.menuList的数据,将数据插入重新插入到localstorage中
    const obj: All = {
      id: new Date().getTime(),
      isCate: Number(objCan.isCate),
      title: objCan.title,
      content: objCan.content
    }
    // push
    this.MenuList.push(obj)
    // 存入localstorage
    localStorage.setItem('Menu', JSON.stringify(this.MenuList))
    // 因为怎么说呢,vue2对push方法的监听是不能及时监听到的,实现不了响应式,所以我们在这里需要重新调用一边this.Read方法对this.MenuList进行重新赋值
    this.Read()
  }
  // 修改方法
  Edit(objCan:any): void {
    // 存入localstorage
    let obj: any = this.MenuList.filter((item: any) => {
      return item.id === objCan.id
    })[0]

    obj.isCate = Number(objCan.isCate)
    obj.title = objCan.title
    obj.content = objCan.content
    // 栈堆指向问题,指向的都是同一个地址,直接使用this.menuList即可
    localStorage.setItem('Menu', JSON.stringify(this.MenuList))
    this.Read()
  }
  // 删除方法
  Del(objCan: any): void {
    let i:number = this.MenuList.indexOf(objCan)
    this.MenuList.splice(i,1)
    localStorage.setItem('Menu', JSON.stringify(this.MenuList))
    this.Read()
  }

}
export default CurdMethods

第三步

App.vue文件

<template>
  <div id="app">
    <ul>
      <li @click="cate()">全部li>
      <li @click="cate(0)">学习li>
      <li @click="cate(1)">工作li>
      <li @click="cate(2)">热门li>
    ul>
    <button @click="dialogVisible = true">新增button>
    <div class="blog">
      <NavItem v-for="item in $store.state.menuList.MenuList" :key="item.id" :menuitem="item" />
    div>

    <el-dialog title="提示" :visible="dialogVisible" width="30%">
      标题
      <el-input v-model="form.title">el-input>
      内容
      <el-input v-model="form.content">el-input>
      类型
      <el-select v-model="form.isCate" placeholder="选择类型">
        <el-option label="学习" :value="0">el-option>
        <el-option label="工作 " :value="1">el-option>
        <el-option label="热门 " :value="2">el-option>
      el-select>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消el-button>
        <el-button type="primary" @click="subMethods">确 定el-button>
      span>
    el-dialog>
  div>
template>

<script lang="ts"> //必须要加上lang = ts
import { Component, Vue, Watch } from "vue-property-decorator";
// 引入的NavItem.vue组件 我们可以去使用在下方@Component进行挂载
import NavItem from "./components/NavItem.vue";
// 定义了一个接口 下方指定类型时使用
interface Iform {
  id: number;
  isCate: number;
  title: string;
  content: string;
}
// ts用来引组件的
@Component({
  components: {
    NavItem
  }
})
export default class App extends Vue {
  // 如果想要声明原来的data数据直接写在里面即可
  // 像created mounted 也是可以直接去使用的,我们不需要在用对象的方式去写代码
  // 弹出框展示
  dialogVisible: boolean = false;
  // 增加内容展示
  form: Iform = {
    isCate: 0,
    id: -1,
    title: "",
    content: ""
  };
  // 点击确定事件
  subMethods(): void {
    this.$store.commit('Add',this.form);
    this.form.title = ''
    this.form.content = ''
    this.dialogVisible = false;
  }
  // 筛选类型
  cate(isCate:number):void{
    this.$store.commit('Cate',isCate);
  }
}
script>

<style>
ul {
  display: flex;
  justify-content: space-around;
}
li {
  list-style-type: none;
  padding: 10px 30px;
  font-size: 20px;
  font-weight: 800;
  background: chartreuse;
}
.blog {
  display: flex;
  flex-wrap: wrap;
}
style>

第四步

src/component/NavItem.vue

<template>
  <div class="content">
    <div class="edit" @click="editMethods">Editdiv>
    <p>标题:{{ menuitem.title }}p>
    <p>内容:{{ menuitem.content }}p>
    <p>所属分类:{{ cate }}p>
    <div class="del" @click="delMethods">Deldiv>
    <el-dialog title="修改" :visible="dialogVisible" width="30%">
      标题
      <el-input v-model="form.title">el-input>
      内容
      <el-input v-model="form.content">el-input>
      类型
      <el-select v-model="form.isCate" placeholder="选择类型">
        <el-option label="学习" :value="0">el-option>
        <el-option label="工作 " :value="1">el-option>
        <el-option label="热门 " :value="2">el-option>
      el-select>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消el-button>
        <el-button type="primary" @click="subMethods">确 定el-button>
      span>
    el-dialog>
  div>
template>

<script lang="ts">
import { Component, Vue, Prop, Watch } from "vue-property-decorator";
interface Iform {
  id: number;
  isCate: number;
  title: string;
  content: string;
}
@Component
export default class NavItem extends Vue {
  cate!: string; // 判断类型
  // 数据初始化双绑
  form: Iform = {
    id: -1,
    isCate: 0,
    title: "",
    content: ""
  };
  dialogVisible: boolean = false;
  // 获取 父组件传值
  @Prop() menuitem!: any;
  // watch侦听器
  @Watch("menuitem", { /*immediate: true,*/ deep: true }) //用于深度监听对象  immediate上来就执行
  getmenuitem(newVal: object, oldVal: object) {
    if (this.menuitem.isCate === 0) {
      this.cate = "学习";
    } else if (this.menuitem.isCate === 1) {
      this.cate = "工作";
    } else {
      this.cate = "热门";
    }
  }
  // 修改方法
  editMethods() {
    this.dialogVisible = true;
    this.form.id = this.menuitem.id;
    this.form.isCate = this.menuitem.isCate;
    this.form.title = this.menuitem.title;
    this.form.content = this.menuitem.content;
  }
  // 提交修改事件方法
  subMethods() {
    this.$store.commit('Edit',this.form);
    this.dialogVisible = false;
  }
  // 删除事件
  delMethods() {
    this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    })
      .then(() => {
        this.$store.commit('Del',this.form);
        this.$message({
          type: "success",
          message: "删除成功!"
        });
      })
      .catch(() => {
        this.$message({
          type: "info",
          message: "已取消删除"
        });
      });
  }
  created() {
    // 初始化判断类型
    if (this.menuitem.isCate === 0) {
      this.cate = "学习";
    } else if (this.menuitem.isCate === 1) {
      this.cate = "工作";
    } else {
      this.cate = "热门";
    }
  }
}
script>

<style scoped>
.content {
  width: 200px;
  height: 200px;
  margin: 10px;
  background: #cccccc;
  text-align: center;
}
.edit {
  background: blueviolet;
  width: 50px;
  margin: 0 auto;
  border-radius: 20px;
}
.del {
  background: red;
  width: 50px;
  margin: 0 auto;
  border-radius: 20px;
}
style>

接下来我们可以看一下目录结构
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第9张图片
最后因为我在项目中使用到了element ui
所以我们还要在项目中进行挂载
然后最后需要完善一下store中的方法
store/index.ts

import Vue from 'vue'
import Vuex from 'vuex'
import MenuList from '../model/CurdMethods'


const store = new Vuex.Store({
  state: {
    menuList: new MenuList()
  },
  mutations: {
    // 下方的方法其实就是在调用我们new MenuList()这个实例对象中的方法
    Add(state: any, obj: any) {
      state.menuList.Add(obj)
    },
    Edit(state: any, obj: any){
      state.menuList.Edit(obj)
    },
    Del(state: any, obj: any){
      state.menuList.Del(obj)
    },
    // 点击类型进行分类判断的
    Cate(state:any,isCate:number){
      if(isCate==0 || isCate==1 || isCate==2){
        state.menuList.MenuList = state.menuList.Read().filter((item:any)=>{
          return isCate === item.isCate
        })
      }else{
        state.menuList.MenuList = state.menuList.Read()
      }
    }
  }
})
export default store

main.ts

import Vue from 'vue'
import App from './App.vue'
import store from './store'
// 引入 element ui 并挂载
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

最终启动项目 呈现效果
一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第10张图片

码云地址:https://gitee.com/hanbingxu82/vue-ts-curd-local-strage

一篇博客 教会你在Vue中快速上手TypeScript(在Vue中使用typescript)_第11张图片

你可能感兴趣的:(vue,typescript,vue,typescript)