百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

Vue3框架搭建(vue 框架搭建)

ztj100 2025-04-06 00:42 12 浏览 0 评论

目录

  • 二十一、项目搭建规范1、创建项目2、代码规范a、.editorconfig(编辑器编辑风格)b、prettier(代码格式化风格)c、eslint(代码风格检测工具)d、git Husky(提交前代码格式化风格)e、commitizen(提交信息格式化风格)f、commitlint(提交信息风格检测工具)3、项目结构a、vue.config.jsb、vue-routerc、vuexd、element-pluse、axiosf、环境变量g、tsconfig.jsonh、shims-vue.d.ts
  • 二十二、项目实战细节(一)1、获取组件实例的类型2、确定props的类型3、setup顶层编写方式中的props用法4、浏览器的重绘和重排(回流)5、echarts使用canvas或者svg渲染6、setup顶层编写方式中子组件暴露属性和方法的用法
  • 二十三、项目打包和自动化部署1、centos7安装dnf2、dnf方式安装java3、安装jenkins4、dnf方式安装nginx5、dnf方式安装git6、jenkins配置与使用

二十一、项目搭建规范

1、创建项目

  • 命令
vue create vue3-ts
  • 选项
? Please pick a preset: 
    - Manually select features
? Check the features needed for your project: 
    - Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 
    - 3.x
? Use class-style component syntax? 
    - No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? 
    - Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) 
    - No
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): 
    - Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: 
    - Prettier
? Pick additional lint features: 
    - Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? 
    - In dedicated config files
? Save this as a preset for future projects? 
    - No
? Pick the package manager to use when installing dependencies: 
    - NPM

2、代码规范

a、.editorconfig(编辑器编辑风格)

# http://editorconfig.org

root = true

[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行

[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false

b、prettier(代码格式化风格)

  • 安装
npm i -D prettier
  • .prettierrc
{
  "useTabs": false,
  "tabWidth": 2,
  "printWidth": 80,
  "singleQuote": true,
  "trailingComma": "none",
  "semi": false
}
* useTabs:使用tab缩进还是空格缩进,选择false
* tabWidth:tab是空格的情况下,是几个空格,选择2个
* printWidth:当行字符的长度,推荐80,也有人喜欢100或者120
* singleQuote:使用单引号还是双引号,选择true,使用单引号
* trailingComma:在多行输入的尾逗号是否添加,设置为 `none`
* semi:语句末尾是否要加分号,默认值true,选择false表示不加
  • .prettierignore
/dist/*
.local
.output.js
/node_modules/**

**/*.svg
**/*.sh

/public/*
  • package.json
{
  "scripts": {
    "prettier": "prettier --write ."
  }
}

c、eslint(代码风格检测工具)

  • 安装
npm i -D eslint-plugin-prettier eslint-config-prettier
  • .eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true
  },
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/typescript/recommended',
    '@vue/prettier',
    '@vue/prettier/@typescript-eslint',
    // 解决eslint和prettier的冲突
    'plugin:prettier/recommended'
  ],
  parserOptions: {
    ecmaVersion: 2020
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    '@typescript-eslint/no-var-requires': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-non-null-assertion': 'off'
  }
}

d、git Husky(提交前代码格式化风格)

  • 命令
################
# 1、用于拦截git命令
# 2、项目三处变化:
#     - package.json多一个依赖({"devDependencies": {"husky": ""}})
#     - 项目下多一个.husky目录
#     - package.json多一个脚本({"scripts": {"prepare": "husky install"}})
################
npx husky-init && npm install
  • .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint

e、commitizen(提交信息格式化风格)

  • 安装
npm i -D commitizen
  • 命令
################
# 1、项目两处变化:
#     - package.json多一个依赖({"devDependencies": {"cz-conventional-changelog": ""}})
#     - package.json多一个配置
#       ({"config": {"commitizen": {"path": "./node_modules/cz-conventional-changelog"}}})
################
npx commitizen init cz-conventional-changelog --save-dev --save-exact
  • package.json(代码的git提交操作使用此脚本)
{
  "scripts": {
    "commit": "cz"
  }
}
  • 选项
? Select the type of change that you're committing: 
    - 提交的类型
? What is the scope of this change (e.g. component or file name): (press enter to skip) 
    - 提交的范围
? Write a short, imperative tense description of the change (max 87 chars):
    - 提交的简短描述信息
? Provide a longer description of the change: (press enter to skip)
    - 提交的详细描述信息
? Are there any breaking changes? 
    - No
? Does this change affect any open issues? 
    - No

提交的类型

作用

feat

新增特性 (feature)

fix

修复 Bug(bug fix)

docs

修改文档 (documentation)

style

代码格式修改(white-space, formatting, missing semi colons, etc)

refactor

代码重构(refactor)

perf

改善性能(A code change that improves performance)

test

测试(when adding missing tests)

build

变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等)

ci

更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等

chore

变更构建流程或辅助工具(比如更改测试环境)

revert

代码回退

f、commitlint(提交信息风格检测工具)

  • 安装
npm i -D @commitlint/config-conventional @commitlint/cli
  • commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional']
}
  • 命令
################
# 1、项目一处变化:
#     - .husky下多一个commit-msg文件
################
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"

3、项目结构

a、vue.config.js

const path = require('path')

module.exports = {
  // 1、方式一: 通过Vue CLI提供的选项来配置(推荐)
  outputDir: 'dist',
  publicPath: '/',
  // 2、方式二: 通过configureWebpack(与webpack配置选项一致)
  // 2.1、对象:合并webpack配置
  configureWebpack: {
    resolve: {
      alias: {
        components: '@/components'
      }
    }
  },
  // 2.2、函数:修改webpack配置
  /*
  configureWebpack: (config) => {
    config.resolve.alias = {
      '@': path.resolve(__dirname, 'src'),
      components: '@/components'
    }
  },*/
  // 3、方式三:通过chainWebpack(与webpack配置选项一致)
  // 3.1、函数:修改webpack配置
  /*
  chainWebpack: (config) => {
    config.resolve.alias
      .set('@', path.resolve(__dirname, 'src'))
      .set('components', '@/components')
  }*/
}

b、vue-router

  • 安装
npm i -S vue-router@next
  • src/router/index.ts
import { createRouter, createWebHashHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'

const routes: Array = [
  {
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    component: () => import('../views/Home.vue')
  },
  {
    path: '/about',
    component: () => import('../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router
  • src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)
app.use(router)
app.mount('#app')
  • src/App.vue

c、vuex

  • 安装
npm i -S vuex@next
  • src/store/index.ts
import { createStore, useStore as useVuexStore } from 'vuex'
import user, { IUserState } from './modules/user'

export interface IRootState {
  user: IUserState
}

export default createStore({
  modules: {
    user
  }
})

export function useStore() {
  return useVuexStore()
}
  • src/store/modules/user.ts
import { IRootState } from '@/store'

export interface IUserState {
  token: string
  userInfo: {
    id: string
    nickname: string
  }
}

const user: Module = {
  namespaced: true,
  state() {
    return {
      token: '',
      userInfo: {
        id: '',
        nickname: ''
      }
    }
  },
  mutations: {},
  actions: {}
}
export default user
  • src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

const app = createApp(App)
app.use(store)
app.mount('#app')
  • src/App.vue


<script lang="ts">
import { defineComponent } from 'vue'
import { useStore } from '@/store'

export default defineComponent({
  setup() {
    const store = useStore()
    console.log(store.state.user.token)
    return {}
  }
})
</script>


d、element-plus

  • 安装
npm i -S element-plus
  • src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
  • src/App.vue

e、axios

  • 安装
npm i -S axios
  • 知识点
* Promise指定了泛型,则resolve(res)和.then(res=>{})的res就是any类型
* axios配置默认值优先级:请求的config参数 > 实例的defaults属性
* axios实例多个拦截器会合并,执行顺序是从后往前
  • src/utils/request.ts
import axios from 'axios'
import type { AxiosRequestConfig } from 'axios'
import Cookies from 'js-cookie'

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})

service.interceptors.request.use(
  (config) => {
    // 1、请求头添加令牌
    const token = Cookies.get('token')
    if (token && config.headers) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

service.interceptors.response.use(
  (response) => {
    // 2、处理后端接口统一响应结果的状态码
    switch (response.data.code) {
      case 999:
        console.log('错误')
        break
      default:
    }
    return response
  },
  (error) => {
    // 3、处理http的状态码
    switch (error.response.status) {
      case 401:
        console.log('未认证或令牌过期')
        break
      case 403:
        console.log('无权限访问拒绝')
        break
      default:
    }
    return Promise.reject(error)
  }
)

interface IResponseBody {
  code: number
  data: T
  message: string
}

export default function (
  config: AxiosRequestConfig
): Promise<IResponseBody> {
  return service(config).then((res) => {
    return res.data
  })
}
  • src/api/user.ts
import request from '@/utils/request'

export function login(data: any) {
  return request({
    url: '/user/login',
    method: 'post',
    data
  })
}
  • src/App.vue


<script lang="ts">
import { defineComponent } from 'vue'
import { login } from '@/api/user'

export default defineComponent({
  setup() {
    login({}).then((res) => {
      console.log(res)
    })
    return {}
  }
})
</script>


f、环境变量

* 模式:
    - 脚本命令:vue-cli-service serve(默认--mode development)
      引用文件:.env.development
      NODE_ENV:process.env.NODE_ENV = "development"
    - 脚本命令:vue-cli-service build(默认--mode production)
      引用文件:.env.production
      NODE_ENV:process.env.NODE_ENV = "production"
    - 脚本命令:vue-cli-service build --mode staging(手动指定)
      引用文件:.env.staging
      NODE_ENV:process.env.NODE_ENV = "staging"
* NODE_ENV变量无需手动赋值
* 其他变量应以VUE_APP_开头才会自动注入到代码中
* .env优先级小于.env.development或.env.production等

g、tsconfig.json

{
  "compilerOptions": {
    // 目标代码:babel编译(esnext),tsc编译(es5)
    "target": "esnext",
    // 目标代码模块化方案:es模块化方案(esnext),模块化方案混合使用(umd)
    "module": "esnext",
    // ts严格模式
    "strict": true,
    // jsx处理:不转化处理(preserve)
    "jsx": "preserve",
    // 导入功能辅助
    "importHelpers": true,
    // 解析模块方式:后缀名顺序查找文件(node)
    "moduleResolution": "node",
    // 跳过第三方库的类型检测
    "skipLibCheck": true,
    // 源代码模块化方案:模块化方案混合使用
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    // 是否生成映射文件
    "sourceMap": true,
    // 文件解析路径
    "baseUrl": ".",
    // 解析类型
    "types": [
      "webpack-env"
    ],
    // 路径别名(与webpack配置对应)
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    // 基础类型库
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

h、shims-vue.d.ts

/* eslint-disable */
/**
 * 1、声明.vue文件:.vue文件导出的component对象的类型是DefineComponent<{}, any>
 * 2、.vue文件defineComponent函数:
 *     - 源码:function defineComponent(options) {return options}
 *     - 作用:可以使options具有类型限制
 */
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, any>
  export default component
}

二十二、项目实战细节(一)

1、获取组件实例的类型

  • 父组件


<script lang="ts">
import { defineComponent, ref } from 'vue'
import SonComponent from './son-component.vue'

export default defineComponent({
  components: { SonComponent },
  setup() {
    const sonComponentRef = ref()
    type SonComponentType = InstanceType

    const clickHandler = () => {
      /**
       * 1、函数签名以new关键字为前缀:
       *     - var BankAccount: new() => BankAccount;
       *       则BankAccount函数只能以new BankAccount()方式调用
       * 2、InstanceType获取构造函数的实例类型:
       *     - InstanceType;
       *       获取子组件实例的类型
       */
      const sonComponentInstance: SonComponentType = sonComponentRef.value
      // 3、组件实例中的属性并不是ref对象,而是proxy对象,所以不需要.value
      sonComponentInstance.person.age--
    }

    return {
      sonComponentRef,
      clickHandler
    }
  }
})
</script>
  • 子组件


<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const person = ref({
      name: '黄婷婷',
      age: 18
    })

    const clickHandler = () => {
      person.value.age++
    }

    return {
      person,
      clickHandler
    }
  }
})
</script>

2、确定props的类型



<script lang="ts">
import { defineComponent, PropType } from 'vue'

interface IPerson {
  username: string
  age: number
}

export default defineComponent({
  props: {
    persons: {
      type: Array as PropType,
      required: true
    }
  },
  setup(props) {
    props.persons.forEach((item) => {
      console.log(item.username)
    })
    return {}
  }
})
</script>


3、setup顶层编写方式中的props用法



<script lang="ts" setup>
import * as echarts from 'echarts'
import { EChartsOption } from 'echarts'
import { ref, onMounted, withDefaults, defineProps } from 'vue'

const props = withDefaults(
  defineProps<{ options: echartsoption required: true width: string height: string>(),
  {
    width: '100%', // defaults: '100%'
    height: '100%'
  }
)

const echartsDivRef = ref()

onMounted(() => {
  const echartsInstance = echarts.init(echartsDivRef.value!, 'light', {
    renderer: 'svg'
  })
  echartsInstance.setOption(props.options)
})
</script>

4、浏览器的重绘和重排(回流)

* 重绘和回流:
    - 重绘:比如颜色的改变,不会影响后续节点
    - 回流:比如布局的改变,会影响后续节点,影响性能的关键因素
* css优化:
    - transform替代position
    - 避免使用table布局
    - visibility: hidden替代display: none
    - 样式尽可能设置在DOM树的末端,限制回流的范围,减少影响的节点
    - 避免使用包含选择器(div > span)和css表达式(calc())
* js优化:
    - 避免频繁操作DOM(虚拟节点)
    - 避免频繁读取会引发回流的属性(offset)

5、echarts使用canvas或者svg渲染

* canvas:大数据量的图表、视觉特效
* svg(推荐):内存占用低、浏览器缩放不会模糊(矢量图)

6、setup顶层编写方式中子组件暴露属性和方法的用法



<script lang="ts" setup>
import { defineExpose, ref } from 'vue'

const person = ref({ name: '黄婷婷', age: 18 })
const clickHnadler = () => {
  console.log('黄婷婷')
}

// 父组件ref方式调用子组件方法和获取子组件属性
defineExpose({
  person,
  clickHnadler
})
</script>

二十三、项目打包和自动化部署

1、centos7安装dnf

yum install epel-release -y
yum install dnf -y
# 查看是否安装成功
dnf

2、dnf方式安装java

dnf search java-1.8
dnf install java-1.8.0-openjdk.x86_64 -y
# 查看是否安装成功
java

3、安装jenkins

  • dnf方式安装jenkins(失败)
cd /etc/yum.repos.d/
wget http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
vi jenkins.repo
# baseurl=http://pkg.jenkins.io/redhat,保存退出
dnf install jenkins -y
  • rpm方式安装jenkins
# https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat/:清华大学开源软件镜像站,下载jenkins软件包
dnf install daemonize -y
rpm -ivh jenkins-2.332-1.1.noarch.rpm
  • 启动服务
# 启动服务(默认端口号8080)
systemctl start jenkins
# 查看状态
systemctl status jenkins
# 开机自启
systemctl enable jenkins

4、dnf方式安装nginx

  • 安装
dnf install nginx -y
  • 启动服务
# 启动服务(默认端口80)
# index页面目录:/usr/share/nginx/html/
# nginx配置文件:vi /etc/nginx/nginx.conf
systemctl start nginx
# 查看状态
systemctl status nginx
# 开机自启
systemctl enable nginx

5、dnf方式安装git

dnf install git -y

6、jenkins配置与使用

  • jenkins初始化
* 按提示输入密码
* 安装推荐的插件
  • jenkins安装nodejs插件
* 系统管理 -> 
  插件管理 -> 
  可选插件 -> 
  搜索nodejs并选择 ->
  download now and install after restart ->
  安装完成后重启jenkins(空闲时)
* 系统管理 -> 
  全局工具配置 -> 
  nodejs安装 -> 
  设置别名选择版本(自动安装应是选中状态) ->
  保存
  • jenkins配置用户
# 默认用户是jenkins,访问一些文件会有权限问题
vi /etc/sysconfig/jenkins
# 设置JENKINS_USER="root"
# 重启jenkins
systemctl restart jenkins
  • jenkins任务
* 新建任务 ->
  输入任务名 ->
  构建一个自由风格的软件项目 ->
  确定
* 描述
* 源码管理 ->
  git ->
  仓库URL ->
  添加凭证 ->
  指定分支
* 构建触发器(手动则跳过此步) ->
  定时构建
* 构建环境 ->
  Provide Node & npm bin/ folder to PATH
* 构建 ->
  执行shell
* 保存  
  • shell
# shell
pwd
node -v
npm -v
npm install 
npm run build
pwd
echo '构建成功'
ls
rm -rf /usr/share/nginx/html/* 
cp -rf ./dist/* /usr/share/nginx/html/
  • 定时构建的触发器规则
#每半小时构建一次OR每半小时检查一次远程代码分支,有更新则构建
H/30 * * * *
#每两小时构建一次OR每两小时检查一次远程代码分支,有更新则构建
H H/2 * * *
#每天凌晨两点定时构建
H 2 * * *
#每月15号执行构建
H H 15 * *
#工作日,上午9点整执行
H 9 * * 1-5
#每周1,3,5,从8:30开始,截止19:30,每4小时30分构建一次
H/30 8-20/4 * * 1,3,5

相关推荐

Vue 技术栈(全家桶)(vue technology)

Vue技术栈(全家桶)尚硅谷前端研究院第1章:Vue核心Vue简介官网英文官网:https://vuejs.org/中文官网:https://cn.vuejs.org/...

vue 基础- nextTick 的使用场景(vue的nexttick这个方法有什么用)

前言《vue基础》系列是再次回炉vue记的笔记,除了官网那部分知识点外,还会加入自己的一些理解。(里面会有部分和官网相同的文案,有经验的同学择感兴趣的阅读)在开发时,是不是遇到过这样的场景,响应...

vue3 组件初始化流程(vue组件初始化顺序)

学习完成响应式系统后,咋们来看看vue3组件的初始化流程既然是看vue组件的初始化流程,咋们先来创建基本的代码,跑跑流程(在app.vue中写入以下内容,来跑流程)...

vue3优雅的设置element-plus的table自动滚动到底部

场景我是需要在table最后添加一行数据,然后把滚动条滚动到最后。查网上的解决方案都是读取html结构,暴力的去获取,虽能解决问题,但是不喜欢这种打补丁的解决方案,我想着官方应该有相关的定义,于是就去...

Vue3为什么推荐使用ref而不是reactive

为什么推荐使用ref而不是reactivereactive本身具有很大局限性导致使用过程需要额外注意,如果忽视这些问题将对开发造成不小的麻烦;ref更像是vue2时代optionapi的data的替...

9、echarts 在 vue 中怎么引用?(必会)

首先我们初始化一个vue项目,执行vueinitwebpackechart,接着我们进入初始化的项目下。安装echarts,npminstallecharts-S//或...

无所不能,将 Vue 渲染到嵌入式液晶屏

该文章转载自公众号@前端时刻,https://mp.weixin.qq.com/s/WDHW36zhfNFVFVv4jO2vrA前言...

vue-element-admin 增删改查(五)(vue-element-admin怎么用)

此篇幅比较长,涉及到的小知识点也比较多,一定要耐心看完,记住学东西没有耐心可不行!!!一、添加和修改注:添加和编辑用到了同一个组件,也就是此篇文章你能学会如何封装组件及引用组件;第二能学会async和...

最全的 Vue 面试题+详解答案(vue面试题知识点大全)

前言本文整理了...

基于 vue3.0 桌面端朋友圈/登录验证+60s倒计时

今天给大家分享的是Vue3聊天实例中的朋友圈的实现及登录验证和倒计时操作。先上效果图这个是最新开发的vue3.x网页端聊天项目中的朋友圈模块。用到了ElementPlus...

不来看看这些 VUE 的生命周期钩子函数?| 原力计划

作者|huangfuyk责编|王晓曼出品|CSDN博客VUE的生命周期钩子函数:就是指在一个组件从创建到销毁的过程自动执行的函数,包含组件的变化。可以分为:创建、挂载、更新、销毁四个模块...

Vue3.5正式上线,父传子props用法更丝滑简洁

前言Vue3.5在2024-09-03正式上线,目前在Vue官网显最新版本已经是Vue3.5,其中主要包含了几个小改动,我留意到日常最常用的改动就是props了,肯定是用Vue3的人必用的,所以针对性...

Vue 3 生命周期完整指南(vue生命周期及使用)

Vue2和Vue3中的生命周期钩子的工作方式非常相似,我们仍然可以访问相同的钩子,也希望将它们能用于相同的场景。...

救命!这 10 个 Vue3 技巧藏太深了!性能翻倍 + 摸鱼神器全揭秘

前端打工人集合!是不是经常遇到这些崩溃瞬间:Vue3项目越写越卡,组件通信像走迷宫,复杂逻辑写得脑壳疼?别慌!作为在一线摸爬滚打多年的老前端,今天直接甩出10个超实用的Vue3实战技巧,手把...

怎么在 vue 中使用 form 清除校验状态?

在Vue中使用表单验证时,经常需要清除表单的校验状态。下面我将介绍一些方法来清除表单的校验状态。1.使用this.$refs...

取消回复欢迎 发表评论: