vue3+elementplus(js+vuex)实现增删改查
doubleyong
2022年11月09日 22:59
收录于文集
共59篇

1、创建项目,使用vite

    npm init vite@latest 项目名     选择 vue3     选择 javascript     cd  项目名 :进入项目文件夹     npm i : 安装依赖包     npm run dev  :运行项目

2、项目架构搭建

2.1 创建对应文件夹 如下图

2.2 下载如下安装包: 单独安装包: npm i axios  vuex  vue-router (同时安装多个包,写上安装包的名称,以空格分隔即可)

2.3 路由与main.js的关联 router/index.js 文件内容:

代码块
JavaScript
自动换行
复制代码
import { createRouter, createWebHashHistory } from 'vue-router'
import Login from '../views/Login.vue'

const routes = [
  {
    path: '/',
    component: Login
  }
]

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

export default router
复制成功

main.js中引用路由

代码块
JavaScript
自动换行
复制代码
import router from './router'
createApp(App).use(router).use(store).use(ElementPlus).mount('#app')
复制成功

2.4 store与main.js的关联 store/index.js 文件内容

代码块
JavaScript
自动换行
复制代码
import { createStore } from 'vuex'

import admin from './admin'
export default createStore({
  state:{},
  getters: {},
  mutations: {},
  actions: {},
  modules: {
    admin
  }
})
复制成功

main.js中引入store

代码块
JavaScript
自动换行
复制代码
import store from './store'
createApp(App).use(router).use(store).use(ElementPlus).mount('#app')
复制成功

2.5 axios 的封装 将 axios 封装在 utils/axios.js 文件中

代码块
JavaScript
自动换行
复制代码
import axios from 'axios'
import store from './../store'
const ConfigBaseURL = 'http://localhost:9999';


// 让ajax携带cookie(自动携带本地所有cookie)s
axios.defaults.withCredentials=true;
// 使用create方法创建axios实例
const Service = axios.create({
    baseURL: ConfigBaseURL, //1. 设置默认地址
    timeout: 7000 // 2. 请求超时时间
})


//3. 给POST请求添加请求头设置(不同项目,值不一样)
Service.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';

//4.1 添加请求拦截器
Service.interceptors.request.use(config => {
    return config
})

//4.2 添加响应拦截器
Service.interceptors.response.use(response => {
    console.log("axios 的响应拦截")
    return response
}, error => {

    return Promise.reject(error)
})

export default Service;
复制成功

3、session 登录前端与后端设置 本项目采用session登录 ,需要进行相关设置,才可使用,配置如下 : 参考链接:https://bugshouji.com/mybug3/t23251

3.1 前端设置 axios文件中,设置 axios.defaults.withCredentials=true;  已经在axios.js中添加

代码块
JavaScript
自动换行
复制代码
// 让ajax携带cookie(自动携带本地所有cookie)s
axios.defaults.withCredentials=true;
// 使用create方法创建axios实例
const Service = axios.create({
    baseURL: ConfigBaseURL, //1. 设置默认地址
    timeout: 7000 // 2. 请求超时时间
})
复制成功

3.2 后端设置(nodejs) 跨域设置,且设置Access-Control-Allow-Credentials 为true;

代码块
JavaScript
自动换行
复制代码
app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "http://localhost:5173");
    res.header("Access-Control-Max-Age", "3600");
    res.header("Access-Control-Allow-Credentials", "true");
    res.header("Access-Control-Allow-Headers", "X-Requested-With,X_Requested_With,Content-Type");
    res.header("Access-Control-Allow-Methods", 'PUT, POST, GET, DELETE, OPTIONS');
    // res.header("Access-Control-Allow-Credentials", "true");
    next();
});
复制成功

除此之外注意:当前端配置withCredentials=true时, 后端配置Access-Control-Allow-Origin不能为*, 必须是相应地址否则报错:Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin&#​39; header in the response must not be the wildcard '*&#​39; when the request's credentials mode is &#​39;include'. The credentials mode of requests initiat

4、element-plus引入

下载

npm install element-plus

main.js中引入

代码块
JavaScript
自动换行
复制代码
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).use(router).use(store).use(ElementPlus).mount('#app')
复制成功

5、element-plus el-tableV2 虚拟化表格

5.1 columns 列名的配置信息 在设置columns属性时,其中的宽度字段(width)必须设置值(只能是数字类型)且每一列都要设置,不然会出现数据不显示或是只显示一列的情况。

代码块
JavaScript
自动换行
复制代码
const columns = [
{
    key: "id",
    dataKey: "id",//需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填id
    title: "id",//显示在单元格表头的文本
    width: 80,//当前列的宽度,必须设置
    fixed: true//是否固定列
},
{
    key: "name",
    dataKey: "name",//需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填name
    title: "姓名",
    width: 100,
    fixed: true
}]
复制成功

5.2 自定义单元格内容

自定义单元格渲染器的字段是cellRenderer,类型为VueComponent /(props: CellRenderProps) => VNode

方法一:主要实现 h 函数: 示例:直接从UI框架中引入,然后在h函数的第一个参数中传入组件,需要注意的是,如果第一个参数直接传入字符串如’ElTag’,是渲染无效的,普通的html标签是可以的,第三个参数如果传入的数据是字符串文本,控制台会有警告信息,提示换为函数形式更佳

代码块
JavaScript
自动换行
复制代码
import { ref, h } from "vue";
import { ElMessageBox, ElMessage, ElButton ,ElTag} from "element-plus";
//columns 是一个数组,里面的值为每一列的配置信息
const columns = [
 {
            key: "state",
            dataKey: "state",
            title: "状态",
            width: 80,
            cellRenderer: ({ cellData }) =>
            h(
                ElTag,
                { type: cellData == "1" ? "success" : "danger" },
                { default: () => cellData == "1" ? "有效" : "无效" }//也可以写成字符串如'这是标签内容',但控制台会有警告
            )
 }
]
复制成功

方法二:使用jsx的方式就比较简捷了,需要在script标签设置lang属性等于jsx,在cellRenderer函数中可以直接使用jsx的语法和UI组件(还有自定义组件), 示例如下:

代码块
JavaScript
自动换行
复制代码
 const columns = [{
            key: "handle",
            title: "操作",
            width: 200,
            align: "center",
            cellRenderer: ({rowData}) => (
            <>
                <el-button
                type="danger"
                icon={Delete}
                onClick={handleDelete.bind(this, rowData.admin_no)}
                >
                删除
                </el-button>
                <el-button
                type="primary"
                icon={Edit}
                onClick={handleUpdate.bind(this, rowData.admin_no)}
                >
                修改
                </el-button>
            </>
            ),
        }]
复制成功

使用 jsx 的配置参考链接:https://bugshouji.com/shareweb/t23249

5.3 删除的实现 需要提示,需要使用 import 引入对应的插件 import { ElMessage, ElMessageBox } from "element-plus&#​34;;

代码块
JavaScript
自动换行
复制代码
//删除操作
const handleDelete = (data) => {
  ElMessageBox.confirm(`确定删除 ${data.rowData.name}?`, "提 示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      tableData.value.splice(data.rowIndex, 1);
      ElMessage({
        type: "success",
        message: "删除成功",
      });
    })
    .catch(() => {
      ElMessage({
        type: "info",
        message: "取消删除",
      });
    });
};
复制成功

5.4 icon 图标的正常显示配置

参考:https://bugshouji.com/shareweb/t23250 因element-plus/icons改变成了svg,故显示 icon 需要进行如下配置: 1.安装 @element-plus/icons-vue npm install @element-plus/icons-vue 2. 使用 在引用图标的页面中将要使用的图标引入,作为js对象,代码如下:

代码块
JavaScript
自动换行
复制代码
<script>
 import { Edit,Share } from "@element-plus/icons-vue";
 export default {
    setup() {
     return {
       Edit,
       Share
     }
    }
   }
</script>
复制成功

使用方式和elemunt-ui3官网一致

代码块
JavaScript
自动换行
复制代码
<div class="flex">
   <el-button type="primary" :icon="Edit" />
   <el-button type="primary" :icon="Share" />
   <el-button type="primary">
     Upload<el-icon class="el-icon--right"><Upload /></el-icon>
   </el-button>
 </div>
复制成功

或者采用 jsx 的语法,使用 {} 显示变量

代码块
JavaScript
自动换行
复制代码
const columns = [
  {
            key: "handle",
            title: "操作",
            width: 200,
            align: "center",
            cellRenderer: (data) => (
            <>
                <el-button
                type="danger"
               icon={Delete}
                onClick={handleDelete.bind(this, data)}
                >
                删除
                </el-button>
                <el-button
                type="primary"
                icon={Edit}
                onClick={handleDelete.bind(this, data)}
                >
                修改
                </el-button>
            </>
            ),
        }
]
复制成功

6、el-pagination 分页组件

代码块
JavaScript
自动换行
复制代码
  <el-pagination background
         layout="prev, pager, next"
         :total="total"
          @current-change="handleCurrentChange"
          :current-page.sync="currentPage"
          :page-size="pageSize"
          />
复制成功

total , currentPage,pageSize 均为计算属性, 代码如下:

代码块
JavaScript
自动换行
复制代码
const total =  computed(()=> getters['admin/getTotal']); //获取总条数
const currentPage =  computed(()=> getters['admin/getCurrentPage']); //获取总条数
const pageSize =  computed(()=> getters['admin/getPageSize']); //获取总条数
复制成功

@current-change="handleCurrentChange&#​34;,当页发生变化 ,执行handleCurrentChange方法

代码块
JavaScript
自动换行
复制代码
//点击页码按钮事件
const handleCurrentChange =(page)=>{
   dispatch("admin/setCurrentPage",page); //修改vuex中存储的currentPage的值
   getAdminListBySearchAndPage(); //页码变化重新获取数据
}
复制成功

store/admin.js

代码块
JavaScript
自动换行
复制代码
var state = {
    currentPage:1, //当前页
    pageSize:4,   //每页显示条数
    totalSize:0,  //总条数
    totalPage:0,   //总页码
    data:[], //用户显示table的数据列表
    searchName:""  //搜索的姓名
  }
  
  // 定义getters 读取状态
  var getters = {
     getList(state){
       return [...state.data]
     },
     getTotal(state){
       return state.totalSize;
     },
     getPageSize(state){
      return state.pageSize;
      },
      getCurrentPage(state){
        return state.currentPage;
      },
      getSearchName(state){
        return state.searchName;
      }
  }
  
  // 定义action,要执行的操作,如流程判断,异步请求等
  var actions = {
     setAdminData({commit},data){
       commit('setAdminData',data);
     },
     setCurrentPage({commit},currentPage){
      commit('setCurrentPage',currentPage);
    },
     setTotalSize({commit},num){
      commit('setTotalSize',num);
    },
    setSearchName({commit},name){
      commit('setSearchName',name);  
    }
  }
  
  // 处理状态的改变
  var mutations = {
    setAdminData(state,data){
      state.data=[...data];
    },
    setTotalSize(state,num){
      state.totalSize= num;
      state.totalPage= Math.ceil(num/state.pageSize);
    },
    setSearchName(state,name){
      state.searchName = name;
    }, 
    setCurrentPage(state,currentPage){
      state.currentPage = currentPage;
    }
  }
  export default {
    namespaced:true, //命名空间
    state,
    getters,
    actions,
    mutations
  }
复制成功

7、service 对增删改查实现中,需要的请求 注: axios()方法,data传递的参数以body的形式接收,params传递的参数,会显示在url后面,使用query的形式接收。 service/admin.js

代码块
JavaScript
自动换行
复制代码
import axios from './../utils/axios'
// 获取管理员数据 根据页面与管理员姓名
function getAdminListBySearchAndPage({currentPage,pageSize,searchName}){
    return axios({
        url:"/getAdminListBySearchAndPage",
        method:"post",
        data:{
            currentPage,
            pageSize,
            searchName
        }
    })
}

// 获取管理员的总条数 根据页面与管理员姓名
function getAdminListBySearchCount({searchName}){
    return axios({
        url:"/getAdminListBySearchCount",
        method:"post",
        data:{
            searchName
        }
    })
}

//删除管理员 
function delAdminById(id){
    return axios({
        url:"/delAdminById",
        method:"get",
        params:{
            id
        }
    })
}

//获取管理员数据,根据管理员id
function getAdminInfoById(id){
    return axios({
        url:"/getAdminInfoById",
        method:"get",
        params:{
            id
        }
    })
}
//更新管理员数据 ,根据管理员id
function updateAdminInfoById(userInfo){
    return axios({
        url:"/updateAdminInfoById",
        method:"post",
        data:userInfo
    })
}


//添加管理员
function add_admin({user,pwd,rePwd,name,type}){
    return axios({
        url:"/addAdmin",
        method:"post",
        data:{
          user,pwd,rePwd,name,type
        }
    })
}
//管理员登录 
function admin_login(user,pwd){
    return axios({
        url:"/admin_login",
        method:"post",
        data:{
           user,pwd
        }
    })
}
export default {
    getAdminListBySearchAndPage,
    getAdminListBySearchCount,
    delAdminById,
    updateAdminInfoById,
    getAdminInfoById,
    admin_login,
    add_admin
}
复制成功

service/index.js 组合所有的service文件

代码块
JavaScript
自动换行
复制代码
import admin from './admin'

export default {
    admin
}
复制成功

8、hooks 实现增删改查所有业务的文件

8.1 路由的相关hook 1. useRouter() 获取路由对象

代码块
JavaScript
自动换行
复制代码
import { useRouter } from 'vue-router' //引入
const router = useRouter();  //获取router对象
 router.push("/login");  //跳转
 router.push({  //跳转带参数
            name: 'adminmodify',
            query: {
                id
            }
        });
复制成功

2. useRoute() 获取当前路由对象

代码块
JavaScript
自动换行
复制代码

import { onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";

const route = useRoute();
onMounted(() => {
  //加载时,显示对应的数据
  const id = route.query.id;
});
复制成功

  

8.2 useStore 使用vuex的hook

import { useStore } from 'vuex&#​39; const { getters, dispatch } = useStore(); 完整代码:

代码块
JavaScript
自动换行
复制代码
import service from './../service/index'
import { ElMessage } from "element-plus";
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'

function adminManage() {
    const router = useRouter();
    const store = useStore();

    async function getAdminInfoById(id) {
        const {data} = await service.admin.getAdminInfoById(id);
        console.log("data",data);
        if (data.code == 200) {
            return data.data;
        } else if (data.code == 201) {
            router.push("/login"); // 跳转到登录
            return null;
        } else {
            //提示错误信息
            ElMessage({
                message: data.message,
                type: 'error',
            });
            return null;
        }

    }
    //获取数据,根据searchName,currentPage,pageSize  
    function getAdminListBySearchAndPage() {
        service.admin.getAdminListBySearchAndPage({
            currentPage: store.state.admin.currentPage,
            pageSize: store.state.admin.pageSize,
            searchName: store.state.admin.searchName
        }).then(({ data }) => {
            if (data.code == 200) {
                console.log(data.data);
                store.dispatch("admin/setAdminData", data.data);
            } else if (data.code == 201) {
                console.log(data.message);
                router.push("/login"); // 跳转到登录
            } else {
                console.log(data);
                //提示错误信息
                ElMessage({
                    message: data.message,
                    type: 'error',
                });
            }
        })
    }
    // 根据searchName获取总条数
    function getAdminListBySearchCount() {
        service.admin.getAdminListBySearchCount({
            searchName: store.state.admin.searchName
        }).then(({ data }) => {
            if (data.code == 200) {
                store.dispatch("admin/setTotalSize", data.data);
            } else if (data.code == 201) {
                router.push("/login"); // 跳转到登录
            } else {
                //提示错误信息
                ElMessage({
                    message: data.message,
                    type: 'error',
                });
            }
        })
    }
    // 删除方法,根据id
    function Handle_del(id) {
        //发起请求
        service.admin.delAdminById(id).then(({ data }) => {
            if (data.code == 200) { //获取成功
                ElMessage({
                    message: '删除成功',
                    type: 'success',
                });
                // 重新获取数据,与总条数
                getAdminListBySearchAndPage();
                getAdminListBySearchCount();
            } else if (data.code == 201) {
                router.push("/login"); // 跳转到登录
            } else {
                //提示错误信息
                ElMessage({
                    message: data.message,
                    type: 'error',
                });
            }
        })
    }
    // 管理员登录 
    function adminLogin(user, pwd) {
        service.admin.admin_login(user, pwd).then(({ data }) => {
            if (data.code == 200) {
                router.push("/index"); // 跳转到登录
                //存储登录用户的信息在vuex中
            } else {
                ElMessage({
                    message: data.message,
                    type: 'error',
                });
            }
        })
    }
    // 添加管理员
    function add_admin(userInput) {
        service.admin.add_admin(userInput).then(({ data }) => {
            if (data.code == 200) {
                ElMessage({
                    message: data.message,
                    type: 'success',
                });
                router.push("/index"); //跳到列表页
            }
            else if (data.code == 201) {
                router.push("/login"); // 跳转到登录
            }
            else {
                ElMessage({
                    message: data.message,
                    type: 'error',
                });
            }
        })
    }
    //更新管理
    function update_admin(userInput){
        service.admin.updateAdminInfoById(userInput).then(({ data }) => {
            if (data.code == 200) {
                ElMessage({
                    message: data.message,
                    type: 'success',
                });
                router.push("/index"); //跳到列表页
            }
            else if (data.code == 201) {
                router.push("/login"); // 跳转到登录
            }
            else {
                ElMessage({
                    message: data.message,
                    type: 'error',
                });
            }
        })
    }

    return {
        getAdminListBySearchAndPage,
        getAdminListBySearchCount,
        getAdminInfoById,
        Handle_del,
        adminLogin,
        add_admin,
        update_admin
    }
}

export default adminManage
复制成功

9、组件结构与路由设置

注:某个默认路径设置显示的组件 ,将path设置为空字符串即可,代码如下: { path: '&#​39;, name: 'adminList&#​39;, component: () => import('../components/admin/list.vue&#​39;), },

router/index.js 文件

完整如下:

代码块
JavaScript
自动换行
复制代码
import { createRouter, createWebHashHistory } from 'vue-router'
import Login from '../views/Login.vue'

const routes = [
  {
    path: '/',
    component: Login
  },
  {
    path: '/index',
    name: 'index',
    component: () => import('../views/AdminView.vue'),
    children:[
      {
        path: '',
        name: 'adminList',
        component: () => import('../components/admin/list.vue'),
    },
      {
          path: 'add',
          name: 'adminAdd',
          component: () => import('../components/admin/add.vue'),
      },
      {
        path: 'update',
        name: 'adminmodify',
        component: () => import('../components/admin/modify.vue'),
    }
    ]
  },

  {
    path: '/login',
    name: 'login',
    component: Login
  }
]

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

export default router
复制成功

10、添加与修改相关知识点

10.1 使用reactive 结合toRefs绑定数据

代码块
JavaScript
自动换行
复制代码
<script setup>
import { reactive, toRefs } from "vue";
const data = reactive({
  user: "",
  pwd: "",
  rePwd: "",
  name: "",
  type: "超级管理员",
});
const { user, pwd, rePwd, name, type } = toRefs(data);
// 此处的user, pwd, rePwd, name, type 即可进行数据绑定
复制成功

10.2 绑定单选按钮 将一组的单选按钮绑定同一个变量, 当变量的值与单选按钮的value值相同时就会被选中。 对应变量的值,为最后被选中按钮的value值

代码块
JavaScript
自动换行
复制代码
<label for="radStudent">学生</label> 
<input id="radStudent" type="radio" value="student" v-model="role">
<label for="radAdmin">管理员</label> 
<input id="radAdmin" type="radio" value="admin"  v-model="role">

<script setup>
   import {reactive,toRefs} from 'vue';
   const data = reactive({
     user:"",
     pwd:"",
     role:"admin"
   })
   const {user,pwd,role} = toRefs(data);
复制成功

10.3 绑定下拉列表 注意: 1. isDelete的类型,要为字符串,如果数据为number 需要进行转换 2. 使用 label 为显示数据,不要写在el-option之间;如:<el-option value="0&#​34;>删除</el-option>绑定数据会出错 3. 绑定的数据 isDetele 是对应项的value值

代码块
JavaScript
自动换行
复制代码
<el-select v-model="isDelete" >
    <el-option label="删除" value="0"></el-option>
    <el-option label="恢复" value="1"></el-option>
</el-select>
复制成功

苟有恒 , 何必三更眠五更起

关注我,一起学习吧