vue的使用

一、下载

官网下载,建议下载长期支持版本

二、Vue项目-创建

创建项目以及安装依赖的过程,都是需要联网的。
1、选择一个文件目录,地址栏目cmd打开小黑框,执行命令:npm init vue@latest
2、执行上述指令,将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具
3、进入项目目录,执行命令安装当前项目的依赖:npm install

三、API风格

1、注意点

​ 选项式 API 在 Vue 2 和 Vue 3 中都是可用的,而组合式 API 则是 Vue 3 特有的新特性,不过可以通过插件形式让 Vue 2 也能享受到。

2、选项式
<template>
  <div>
    <div id="center">
      姓名: <input type="text" name="name" v-model="searchForm.name">

      性别:
      <select name="gender" v-model="searchForm.gender">
        <option value="1">男</option>
        <option value="2">女</option>
      </select>

      职位:
      <select name="job" v-model="searchForm.job">
        <option value="1">讲师</option>
        <option value="2">班主任</option>
        <option value="3">其他</option>
      </select>

      <input class="btn" type="button" value="查询" @click="search">
    </div>


    <table>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>头像</th>
        <th>性别</th>
        <th>职位</th>
        <th>入职时间</th>
        <th>更新时间</th>
      </tr>

      <tr v-for="(user, index) in userList" :key="user.id">
        <td>{{ index + 1 }}</td>
        <td>{{ user.name }}</td>
        <td> <img :src="user.image"> </td>
        <td>{{ user.gender == '1' ? '男' : '女' }}</td>
        <td>
          <span v-if="user.job == 1">讲师</span>
          <span v-else-if="user.job == 2">班主任</span>
          <span v-else>其他</span>
        </td>
        <td>{{ user.entrydate }}</td>
        <td>{{ user.updatetime }}</td>
      </tr>
    </table>
  </div>
</template>

<script>
// 选项式API
import axios from 'axios';
export default {
  data() {
    return {
      //搜索表单数据
      searchForm: {
        name: "",
        gender: "",
        job: ""
      },
      //表格数据
      userList: [
        {
          "id": 1,
          "name": "谢逊",
          "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
          "gender": 1,
          "job": 1,
          "entrydate": "2021-06-09",
          "updatetime": "2021-07-01 00:00:00"
        },
        {
          "id": 2,
          "name": "韦一笑",
          "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
          "gender": 1,
          "job": 1,
          "entrydate": "2021-06-09",
          "updatetime": "2021-07-01 00:00:00"
        },
        {
          "id": 3,
          "name": "黛绮丝",
          "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/3.jpg",
          "gender": 2,
          "job": 2,
          "entrydate": "2021-06-09",
          "updatetime": "2021-07-01 00:00:00"
        },
        {
          "id": 4,
          "name": "殷天正",
          "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
          "gender": 1,
          "job": 3,
          "entrydate": "2021-06-09",
          "updatetime": "2021-07-01 00:00:00"
        }
      ]
    };
  },
  methods: {
    search() {
      axios.get(`https://web-server.itheima.net/emps/list?name=${this.searchForm.name}&gender=${this.searchForm.gender}&job=${this.searchForm.job}`).then((result) => {
        console.log(result.data.data)
        this.userList = result.data.data
      }).catch((err) => {
        //请求失败时进入
      })
    }
  },

  //定义一个钩子函数 mounted,页面加载完毕之后, 发送请求查询所有员工
  mounted() {
    this.search()
  }
};
</script>

<style>
table,
th,
td {
  border: 1px solid #000;
  border-collapse: collapse;
  line-height: 50px;
  text-align: center;
}

#center,
table {
  width: 60%;
  margin: auto;
}

#center {
  margin-bottom: 20px;
}

img {
  width: 50px;
}

input,
select {
  width: 17%;
  padding: 10px;
  margin-right: 30px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.btn {
  background-color: #ccc;
}
</style>
3、组合式
<script setup>
// 组合式API 
import axios from 'axios';
import { ref,reactive, onMounted } from 'vue';
  /* 
  ref:可以定义变量、对象、数组
  reactive:只能定义对象、数组
  ref定义的变量、对象、数组,需要先.value才能取到里面的值
  reactive定义的对象,可以直接取到里面的值 
  */
  let searchForm=reactive({
    'name':'',
    'gender':'',
    'job':'',
  })
  let userList=ref([])

    /*
      基于axios发送异步请求加载数据
      服务器数据地址:https://web-server.itheima.net/emps/list?name=xxx&gender=xxx&job=xxx
    */

    //axios请求写法1
    search=()=>{
    axios.get(`https://web-server.itheima.net/emps/list?name=${searchForm.name}&gender=${searchForm.gender}&job=${searchForm.job}`)..then((result) => {
      console.log(result)
      userList.value=result.data.data
    }).catch((err) => {
      //请求失败时进入
    });
    
  }

  //axios请求写法2
  async function search(){
    const result=await axios.get(`https://web-server.itheima.net/emps/list?name=${searchForm.name}&gender=${searchForm.gender}&job=${searchForm.job}`)
    console.log(result)
    userList.value=result.data.data
  }

  //定义一个钩子函数 mounted,页面加载完毕之后, 发送请求查询所有员工
  onMounted(()=>{
    search()
  })

   

</script>
<template>
  <div>
    <div id="center">
      姓名: <input type="text" name="name" v-model="searchForm.name">

      性别:
      <select name="gender" v-model="searchForm.gender">
        <option value="1">男</option>
        <option value="2">女</option>
      </select>

      职位:
      <select name="job" v-model="searchForm.job">
        <option value="1">讲师</option>
        <option value="2">班主任</option>
        <option value="3">其他</option>
      </select>

      <input class="btn" type="button" value="查询" @click="search">
    </div>


    <table>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>头像</th>
        <th>性别</th>
        <th>职位</th>
        <th>入职时间</th>
        <th>更新时间</th>
      </tr>

      <tr v-for="(user, index) in userList" :key="user.id">
        <td>{{index+1}}</td>
        <td>{{user.name}}</td>
        <td> <img :src="user.image"> </td>
        <td>{{user.gender==1?'男':'女'}}</td>
        <td>
          <span v-if="user.job==1">讲师</span>
          <span v-else-if="user.job==2">班主任</span>
          <span v-else>其他</span>
        </td>
        <td>{{user.entrydate}}</td>
        <td>{{user.updatetime}}</td>
      </tr>
    </table>
  </div>
</template>
  
<style>
table,
th,
td {
  border: 1px solid #000;
  border-collapse: collapse;
  line-height: 50px;
  text-align: center;
}

#center,
table {
  width: 60%;
  margin: auto;
}

#center {
  margin-bottom: 20px;
}

img {
  width: 50px;
}

input,
select {
  width: 17%;
  padding: 10px;
  margin-right: 30px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.btn {
  background-color: #ccc;
}
</style>

四、TypeScripe

1、TypeScripe是JavaScripe的超集
2、安装
安装TS官方提供的编译器:npm install -g typescript (管理员身份运行cmd,全局安装,只需要做一次即可)
3、使用

​ ts给对象类型抽取用interface、给其他类型抽取用type

export let TypeScripeTest = () => {
  // 基础类型
  let name: string = '小江'
  console.log('string测试:', name, typeof name)

  // 联合类型
  type snb = (string | number | Boolean)
  let name2: snb = '小江'
  name2 = 19
  name2 = true
  //联合类型
  let arr: snb[] = ['小江', '小王', 18, 16, true, false]
  console.log('联合类型提取 数组 测试:', arr, typeof arr)

  // 函数类型
  let add3= (a:number,b:number):number=>{
    return a+b
  }
  // 参数后面加?代表参数可选
  function add4(a:number,b?:number):number{
    if(typeof b === 'number'){
      return a+b
    }
    return a
  }

  // 对象类型
  interface userType{
    name:string,
    age?:number
    say():void
  }
  // 接口继承接口,当前userType2拥有2个必须属性,1个必须方法,一个可选属性
  interface userType2 extends userType{
    adrees:string
  }
  let user2:userType2={
    name:'小江',
    adrees:'武汉',
    say(){
      console.log(`name=${this.name},adrees=${this.adrees}`);
    }
  }

  // 泛型类型
  interface userType5<T>{
    name:string,
    age?:number,
    value:T
    say():void
  }
  let user:userType5<String>={
    name: "",
    value: '小江',
    say() {
      console.log('say something');
      
    }
  }
}

五、Element

1、分类
  • Element UI: 基于 Vue 2.x 开发,官网
  • Element Plus: 基于 Vue 3.x 开发,完全兼容 Vue 3.x 的新特性,官网
  • 其他组件库:tdesign,官网
2、安装

参照官方文档,安装Element Plus组件库(在当前工程的目录下):npm install element-plus --save(局部安装,一个项目只需要做一次即可)

3、引入Element组件库
// 在main.ts引入,当前为Element Plus的引入方式,以官网提供的为准
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
4、基础使用案例
<template>
  <div>
    <!-- 搜索栏 -->
    <el-form :inline="true" :model="emp" class="demo-form-inline">
      <el-form-item label="姓名">
        <el-input v-model="emp.name" placeholder="请输入姓名" clearable />
      </el-form-item>
      <el-form-item label="性别">
        <el-select v-model="emp.gender" placeholder="请选择" clearable>
          <el-option label="男" value="1" />
          <el-option label="女" value="2" />
        </el-select>
      </el-form-item>
      <el-form-item label="职位">
        <el-select v-model="emp.job" placeholder="请选择" clearable>
          <el-option label="讲师" value="1" />
          <el-option label="班主任" value="2" />
          <el-option label="其他" value="3" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="search">查询</el-button>
        <el-button type="info" @click="clear">清空</el-button>
      </el-form-item>
    </el-form>
  </div>

  <div>
    <!-- 表格展示数据 -->
    <el-table :data="empList" border style="width: 100%">
      <el-table-column prop="id" label="ID" />
      <el-table-column prop="name" label="姓名" />
      <el-table-column label="头像">
        <!-- 使用插槽,将父组件的数据传递给子组件 -->
        <template #default="scope">
          <img :src="scope.row.image" width="50px" />
        </template>
      </el-table-column>/>
      <el-table-column label="性别">
        <!-- 使用插槽,将父组件的数据传递给子组件 -->
        <template #default="scope">
          <span>{{ scope.row.gender == 1 ? '男' : '女' }}</span>
        </template>
      </el-table-column>/>
      <el-table-column label="职位">
        <template #default="scope">
          <span>{{ ['', '讲师', '班主任', '其他'][scope.row.job] }}</span>
        </template>
      </el-table-column> />
      <el-table-column prop="entrydate" label="入职日期" />
      <el-table-column prop="updatetime" label="更新时间" />
    </el-table>
  </div>

  <div>
    <br>
    <!-- 分页条 -->
    <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[1, 2, 3, 4]"
      :size="size" :disabled="disabled" :background="background" layout="total, sizes, prev, pager, next, jumper"
      :total="empList.length" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
  </div>
</template>
<script setup lang='ts'>
import { ref, onMounted } from 'vue'
import axios from 'axios'

const emp = ref({
  name: '',
  gender: '',
  job: '',
})

const empList = ref([])

//查询按钮
const search = async () => {
  const result = await axios.get(`https://web-server.itheima.net/emps/list?name=${emp.value.name}&gender=${emp.value.gender}&job=${emp.value.job}`)
  empList.value = result.data.data
}

//清空按钮
const clear = () => {
  //清空emp
  emp.value = {
    name: '',
    gender: '',
    job: '',
  }
  search()
}

//加载完成事件
onMounted(() => {
  search()
})


//分页条
const currentPage = ref(4)
const pageSize = ref(1)
const size = ref<ComponentSize>('default')
const background = ref(false)
const disabled = ref(false)

const handleSizeChange = (val: number) => {
  //调用分页查询接口
}
import type { ComponentSize } from 'element-plus';
const handleCurrentChange = async (val: number) => {
  //调用分页查询接口
}
</script>
<style scoped>
.demo-form-inline .el-input {
  --el-input-width: 220px;
}

.demo-form-inline .el-select {
  --el-select-width: 220px;
}
</style>
5、表单校验
<!-- 1、el-form 标签添加ref="ruleFormRef" :rules="rules" -->
<el-form :model="emp" ref="ruleFormRef" :rules="rules">
<script>
import { ElMessage, ElMessageBox, type FormInstance, type FormRules, type UploadProps } from 'element-plus';
const ruleFormRef = ref < FormInstance > ()
const rules = ref < FormRules < EmpModel >> ({
  //EmpModel是自定义的类,username是其中的数据,username[]中即为定义的校验规则
  username: [
    { required: true, message: '用户名为必填项', trigger: 'blur' },
    { min: 2, max: 20, message: '用户名长度为2-20个字', trigger: 'blur' }
  ],
  name: [
    { required: true, message: '姓名为必填项', trigger: 'blur' },
    { min: 2, max: 10, message: '姓名长度为2-10个字', trigger: 'blur' }
  ],
  gender: [{ required: true, message: '性别为必填项', trigger: 'change' }],
  phone: [
    { required: true, message: '手机号为必填项', trigger: 'blur' },
    { pattern: /^1[3-9]\d{9}$/g, message: '请输入合法的手机号', trigger: 'blur' }
  ],
  salary: [
    { pattern: /^[1-9]\d*$/g, message: '请输入合法的数字', trigger: 'blur' }
  ]
})
</script>
6、watch侦听
import { onMounted, ref, watch } from 'vue'
<script>
//当前位watch侦听单个属性
//watch()第一个参数为 被侦听的对象,如果是响应式对象就直接写,普通属性就需要()=>{return 普通属性}
//watch()第二个参数为 侦听到变化时要进行的操作
//watch()第三个参数为 开启深度侦听。默认只侦听一层,侦听对象的普通属性,当前searchEmp.value.date是一个数组,想要侦听,就需要开启深度侦听
watch(()=>searchEmp.value.date,(newValue,oldValue)=>{
  searchEmp.value.begin=newValue&&newValue.length>0?newValue[0]:''
  searchEmp.value.end=newValue&&newValue.length>0?newValue[1]:''
}, { deep: true })
</script>

六、Vue Router

1、Vue的官方路由,Vue中的路由:指的是路径 与 组件 的对应关系
2、Vue Router中的三个核心组成部分
  • router实例,维护了应用的路由信息(routes)
  • :路由链接组件
  • :动态视图组件
3、使用
1、安装、导入
//安装,在node_modules中确认是否安装成功
npm install vue-router@4
//main.ts|main.js中引入
import App from './App.vue'
import router from './router'
//... 其他省略
const app = createApp(App)
app.use(router)

2、新建index.ts
import { createRouter, createWebHistory } from 'vue-router'
//在这个文件中定义了的路径,可以在其他地方使用router.push('/index')进行跳转
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: () => import('../views/layout/index.vue'),
      redirect:'/index',//重定向到 /index
      children: [
        {
          path: 'clazz',//访问当前路径需要父路径——子路径,当前路径为 /clazz
          name: 'clazz',
          component: () => import('../views/clazz/index.vue'),
        },
        {
          path: 'dept',
          name: 'dept',
          component: () => import('../views/dept/index.vue'),
        },
        {
          path: 'emp',
          name: 'emp',
          component: () => import('../views/emp/index.vue'),
        },
        {
          path: 'stu',
          name: 'stu',
          component: () => import('../views/stu/index.vue'),
        },
        {
          path: 'index',
          name: 'index',
          component: () => import('../views/index/index.vue'),
        }
      ]
    }

  ]
})

export default router

3、新建views/layout/index.vue页面
//在vue页面中,通过RouterLink实现路径跳转
<RouterLink to="/dept">部门管理</RouterLink>
<!-- 如果是在element菜单组件中,用router,可以替代RouterLink标签,index的值即为To指向的路径 -->
4、在合适位置定义动态视图组件
 <router-view></router-view>
//当前如果在App.vue中定义该组件,则会先访问../views/layout/index.vue,在访问../views/index/index.vue
//例如:layout/index.vue是一个上面头、左边菜单栏、右边主体的组件,index/index.vue为主体部分的一个画面,就能实现在加载整个页面,并默认加载一个主体的画面

七、vite实现反向代理、拦截器、提取公共路径

1、vite的反向代理只在VScode本地生效,vue项目放在服务器上时,还需要依靠nginx进行反向代理
2、导入工具类request.ts
import axios from 'axios'
import { ElMessage } from 'element-plus'

//创建axios实例对象
const request = axios.create({
  baseURL: 'api',//与vite.config.ts中的反向代理中配置的需要一致,api即为提取的公共路径
  timeout: 600000
})

//axios的响应 response 拦截器
request.interceptors.response.use(
  (result) => { //成功回调
    if(!result.data.code){  //操作失败,弹出错误提示信息
      ElMessage.error(result.data.msg)
    }else{  //操作成功
      if(!result.data.data){   //data中没有数据说明是增删改操作,弹出提示信息
        ElMessage.success(result.data.msg)
      }
      return result.data
    }
  },
  (error) => { //失败回调
    return Promise.reject(error)
  }
)

//axios的响应 request 拦截器
request.interceptors.request.use((config) => {
  // 在发送请求之 --> 携带令牌到服务端 --- header : token
  const loginEmp = loginStore.getLoginInfo();
  if (loginEmp && loginEmp.token) {
    config.headers['token'] = loginEmp.token
  }
  return config;
}, (error) => {
  // 对请求错误做些什么
  return Promise.reject(error);
});

export default request
3、vite.config.ts配置文件添加反向代理
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  
  
    //反向代理
    server: {
      proxy: {
        '/api': {   //匹配 /api开头的路径,与src/utils/request.ts中配置的需要一致
          target: 'http://192.168.69.170:8080',  //目标服务器路径,也就是后端服务器路径
          rewrite: (path) => path.replace(/^\/api/, ''),  //路径重写:http://127.0.0.1:5173/api/depts--->http://localhost:8080/depts
        }
      }
    }
    
    
})

4、axios请求提取到dept.ts
import request from "@/utils/request"
import { type DeptModel, type ResultModel } from "./model"

//查询所有部门
export const selectAllDeptsApi = () => {
  return request.get<any, ResultModel>('/depts')
}
//新增部门
export const addDeptApi = (dept: DeptModel) => request.post<any, ResultModel>('/depts', dept)
//根据id查询部门
export const selectDeptByIdApi = (id: number) => { return request.get<any, ResultModel>('/depts/'+id)}
//根据dept修改部门
export const updateDeptByDeptApi = (dept: DeptModel) => request.put<any, ResultModel>('/depts', dept)

//根据id删除部门
export const deleteDeptByIdApi = (id: number) => request.delete<any, ResultModel>('/depts?id='+id)
5、axios请求调用
<script setup lang="ts">
import { selectAllDeptsApi, addDeptApi, selectDeptByIdApi, updateDeptByDeptApi, deleteDeptByIdApi } from '../../api/model/dept';
import type { DeptModel } from '../../api/model/model';
import { onMounted, ref } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus'

const deptList = ref([])
const dialogFormVisible = ref<boolean>(false)//对话框是否显示
const titleLabel = ref<string>('')//对话框标题
const dept = ref<DeptModel>({ name: '' })
// ----------------------------------------  查询数据  ----------------------------------------
//查询方法
const searsh = async () => {
  const result = await selectAllDeptsApi()
  if (result.code) {
    deptList.value = result.data
  }
}
onMounted(() => {
  searsh()
})


// ----------------------------------------  新增\修改数据  ----------------------------------------
//新增方法
const handleadd = () => {
  titleLabel.value='新增部门'
  dept.value = { name: '' }
  dialogFormVisible.value = true;

}

//修改方法
const handleEdit = async (id: number) => {
  titleLabel.value='修改部门'
  const result = await selectDeptByIdApi(id)
  dept.value = result.data
  dialogFormVisible.value = true;
}
//点击确定
const save = async () => {
  if (dept.value.name == null || dept.value.name == '') {
    ElMessage.error('部门名称为空,不允许操作')
    return
  }
  //id不为空修改,为空新增
  const result = dept.value.id ? await updateDeptByDeptApi(dept.value) : await addDeptApi(dept.value)
  if (result.code) {
    //增、改 成功时刷新
    searsh()
  }
  dialogFormVisible.value = false;
}


// ----------------------------------------  删除数据  ----------------------------------------
//删除方法
const handleDelete =  (id: number) => {
  ElMessageBox.confirm(
    '要删除部门,确认吗?',
    '删除部门',
    {
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      type: 'warning',
    }
  )
    .then(async() => {
      const result = await deleteDeptByIdApi(id)
      if (result.code) {
        //删 成功时刷新
        searsh()
      }
    })
    .catch(() => {
    })




}
</script>

<template>
  <h1>部门管理</h1><br>
  <el-row>
    <el-col :span="2" :offset="22"><el-button type="primary" @click="handleadd">新增</el-button></el-col>
  </el-row><br>

  <!-- 表格 -->
  <el-table :data="deptList" border style="width: 100%">
    <el-table-column type="index" label="ID" width="100" align="center" />
    <el-table-column prop="name" label="部门名称" align="center" />
    <el-table-column prop="updateTime" label="修改时间" align="center" />
    <el-table-column label="操作">
      <template #default="scope">
        <el-button size="small" type="warning" @click="handleEdit(scope.row.id)">
          修改
        </el-button>
        <el-button size="small" type="danger" @click="handleDelete(scope.row.id)">
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>

  <!-- 对话框 -->
  <el-dialog v-model="dialogFormVisible" :title="titleLabel" width="500">
    <el-form :model="dept">
      <el-form-item label="部门名称">
        <el-input v-model="dept.name" autocomplete="off" />
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取消</el-button>
        <el-button type="primary" @click="save">
          确认
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<style scoped></style>

八、Pinia状态管理工具

1、安装引入
//安装
npm install pinia

//引入
// main.js 或 main.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';

const app = createApp(App);

// 创建 Pinia 实例
const pinia = createPinia();

// 将 Pinia 挂载到 Vue 应用实例上
app.use(pinia);

app.mount('#app');
2、自定义stores/counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  //定义响应式数据
  const count = ref(0)
  //定义计算属性(只能获取,无法改变)
  const doubleCount = computed(() => count.value * 2)
  //定义方法
  function increment() {
    count.value++
  }
  //与export配合允许外部调用
  return { count, doubleCount, increment }
})

3、外部调用
import { useCounterStore } from '@/stores/counter'
const store=useCounterStore()
store.count++
4、Pinia持久化
1、默认情况下,浏览器画面一刷新数据就丢失了
2、安装引用
//持久化安装
npm install pinia-plugin-persistedstate

main.ts中引入
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
//pinia中应用piniaPluginPersistedstate
app.use(createPinia().use(piniaPluginPersistedstate))
3、Store中开启pinal持久化功能
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
  ...
  //与export配合允许外部调用
  return { count, doubleCount, increment }
}, {persist: true})//persist:true开启pinal持久化功能

九、打包部署

  1. VScode执行npm脚本build,打包完成的文件都存在dist文件夹中
  2. 下载nginx
  3. 部署:将打包好的 dist 目录下的文件,复制到nginx安装目录的html目录下
  4. 修改nginx.conf文件,配置反向代理
  5. 启动:双击 nginx.exe 文件即可,Nginx服务器默认占用 80 端口号。

十、相关工具

nvm 		允许你在同一台机器上安装和切换不同的 Node.js 版本。
node		JavaScript 运行时环境
npm			Node.js 的默认包管理工具。它允许开发者轻松地安装、分享和管理 Node.js 项目中的依赖包。
cnpm		国内的npm
yarn		包管理工具,npm的加强版
pnpm		现代化的包管理工具,yarn 的加强版
express 	一个轻量级的Node.js框架,非常适合构建RESTful API
nrm 		方便地在不同的源之间切换,尤其是在国内访问 npm 官方源速度较慢的情况下,切换到淘宝源或其他国内源可以显著提高下载速度

安装参考链接

十一、项目创建

  1. npm创建:提供了一些其他插件,创建方式相对简陋,Vue3参考
  2. vite创建:模块集中,可以自由选择,vite官网参考
  3. TDesign模板项目创建:基于PC、移动模板页面,进行二次开发时使用,TDesign官网参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值