你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

vue+element学习记录

2021/12/29 20:53:41

一、Vue介绍

作者:尤雨溪

官网:https://cn.vuejs.org/

       Vue的作者来自中国,叫尤雨溪,大学专业并非是计算机专业,在大学期间他学习专业是室内艺术和艺术史,后来
    读了美术设计和技术的硕士,正是在读硕士期间,他偶然接触到了JavaScript ,从此被这门编程语言深深吸引,
    开启了自己的前端生涯。 于2014年2月,开发了一个前端开发库Vue.js。(引用自百度百科)
  • 问题1:什么是Vue:

    Vue是一个用于构建用户界面的渐进式框架(自由组合,灵活复用),vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(vue-router:跳转,axios:通信,vuex:状态管理)整合。

  • 问题2:相比其它框架有什么优势:

    https://cn.vuejs.org/v2/guide/comparison.html

    Angular:Google收购的前端框架,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念

    React:Facebook出品,一款高性能的JS前端框架;特点是提出了新概念[虚拟DOM]用于
    减少真实DOM操作,在内存中模拟DOM操作,有效的提升了前端渲染效率

    Vue:综合了Angular (模块化)和React (虚拟DOM)的优点,且易用、灵活、高效

  • 问题3:Vue的核心特点:

    • 响应式的数据绑定

    • 可组合的视图组件

    • 虚拟DOM

    • MVVM模式

      MVVM 是一种设计思想
      DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。
      从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。
      在这里插入图片描述

二、Element介绍

vue2.0——https://element.eleme.io/#/zh-CN

vue3.0——https://element-plus.gitee.io/zh-CN/

网站快速成型工具,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库

三、开发环境

brew、node.js、npm、vue-cli 相关概念;

  • brew:是一个软件包管理工具,类似于centos下的yum或者ubuntu下的apt-get,非常方便,免去了自己手动编译安装的不便
  • node.js:运行在服务端的 JavaScript
  • npm:是随同node.js一起安装的包管理工具,是 JavaScript 世界的包管理工具。通过 npm 可以安装、共享、分发代码,管理项目依赖关系(新版的nodejs已经集成了npm)
  • vue-cli:官方提供的一个脚手架,用于快速生成一个 vue 的项目模板;预先定义好的目录结构及基础代码,就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,我们的开发更加的快速;

1、安装 Node.js

安装教程:https://www.runoob.com/nodejs/nodejs-install-setup.html

官网下载: http://nodejs.cn/download/

brew下载:brew install -g node
在这里插入图片描述

设置淘宝镜像加速器

npm install cnpm -g
npm install --registry=https://registry.npm.taobao.org
当后面npm安装失败时,可以使用cnpm替换试试

2、安装VUE-CLI

vue-cli:

在命令台输入, -g表示全局安装

💡 npm install vue-cli -g

查看是否安装成功

💡 vue list
在这里插入图片描述

3、创建一个vue工程

通过vue-cli脚手架创建工程:

vue init webpack vue_test

在这里插入图片描述
在这里插入图片描述

运行项目:
在这里插入图片描述在这里插入图片描述

4、工程结构

5、编辑器环境准备

推荐:vsCode、webStorm、idea(推荐程度按顺序递减)

idea:安装vue.js插件(正版需要破解,社区版搜不到插件)https://blog.csdn.net/m0_47333020/article/details/108182429

webStorm:不需要安装插件(正版需要破解)

vsCode:安装相应的插件(比较方便)https://blog.csdn.net/yujing1314/article/details/90340647

四、基于Vue实现增删改查

效果图
在这里插入图片描述

1、安装路由、element-ui、axios通信工具

npm install vue-router

npm i element-ui -S

npm install axios

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FVRRZpXg-1640781611641)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f0f72c1b-7bf7-48fc-ba14-15481a80631e/Untitled.png)]

2、在main.js中导入组件:根目录——>main.js

import router from ‘./router’
import ElementUI from ‘element-ui’
import ‘element-ui/lib/theme-chalk/index.css’

import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.config.productionTip = false

Vue.use(ElementUI);

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

配置代理(解决跨域问题):根目录——>config——>index.js

proxyTable: {
  '/': {
		// 后端接口请求地址,用于本地执行访问
    target: 'http://114.116.255.239:8081',
    // secure: false,  // 如果是https接口,需要配置这个参数
    changeOrigin: true, // 如果接口跨域,需要进行这个参数配置
    pathRewrite: {
      '^/': ''
    }
  }
}

万能请求工具封装:src——utils——api.js

import axios from 'axios';

//请求封装
let base = "";

//post请求封装,Key、Value形式
export const postKeyValueRequest=(url,params)=>{
  return axios({
    method: 'post',
    url: `${base}${url}`,
    data: params,
    transformRequest: [function (data) {
      let ret = '';
      for(let i in data) {
        ret += encodeURIComponent(i)+'='+encodeURIComponent(data[i])+'&';
      }
      console.log(ret);
      return ret;
    }],
    headers: {
      'Content-Type':'application/x-www-form-urlencoded'
    }
  })
};

//post请求封装,json形式
export const postRequest = (url, params) => {
  return axios({
    method: 'post',
    url: `${base}${url}`,
    data: params
  })
}

//put请求封装
export const putRequest = (url, params) => {
  return axios({
    method: 'put',
    url: `${base}${url}`,
    data: params
  })
}

//get请求封装
export const getRequest = (url, params) => {
  return axios({
    method: 'get',
    url: `${base}${url}`,
    params: params
  })
}

//delete请求封装
export const deleteRequest = (url, params) => {
  return axios({
    method: 'delete',
    url: `${base}${url}`,
    params: params
  })
}

路由配置(页面访问与跳转):src——router——index.js

import Vue from 'vue'
import Router from 'vue-router'

import {postRequest} from "../utils/api";
import {getRequest} from "../utils/api";
import {postKeyValueRequest} from "../utils/api";
import {putRequest} from "../utils/api";
import {deleteRequest} from "../utils/api";

import Emp from "../views/Emp"

//设置为vue的全局变量,方便在组件中引用
Vue.prototype.postRequest = postRequest;
Vue.prototype.getRequest = getRequest;
Vue.prototype.postKeyValueRequest = postKeyValueRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.use(Router)
Vue.config.productionTip = false;

//定义路由规则
export default new Router({
  routes: [
    {
      path: '/',
      name: '职工列表',
      component: Emp,
      hidden : true
    }
  ]
})

Emp.vue内容:

<template>
  <div style="margin: 50px">
     <!--增加-->
     <el-button size="small" type="success" style="margin-bottom:10px" @click="dialogVisible = true">添加</el-button>
     
     <el-input size="small" v-model="employee.name" placeholder="请输入姓名" 
     style="width:200px; margin-left:30px">
     </el-input>

     <el-select v-model="employee.gender" placeholder="性别" size="small">
      <el-option label="All" value=""></el-option>
      <el-option label="男" value="1"></el-option>
      <el-option label="女" value="0"></el-option>
    </el-select>

		<!--搜索-->
    <el-button size="small" type="primary" style="margin-bottom:10px" @click="initData()">搜索</el-button>
     
     <!-- 列表数据 -->
     <el-table
      :data="empList"
      stripe
      style="width: 100%">
      <el-table-column
        type="selection"
        width="50">
      </el-table-column>
      <el-table-column
        prop="id"
        label="id"
        width="180">
      </el-table-column>
      <el-table-column
        prop="name"
        label="姓名"
        width="180">
      </el-table-column>
      <el-table-column
        label="姓别"
        width="180">
        <template #default="scope">
          <el-tag v-if="scope.row.gender === '1'"></el-tag>
          <el-tag v-else type="warning"></el-tag>
        </template>
      </el-table-column>
      <el-table-column
        prop="address"
        label="地址"
        width="180">
      </el-table-column>
      <el-table-column
        prop="email"
        label="邮箱"
        width="180">
      </el-table-column>
      <el-table-column
        prop="phone"
        label="电话"
        width="180">
      </el-table-column>
      <el-table-column
        prop="department" 
        label="部门"
        width="180">
      </el-table-column>
      <el-table-column
        label="操作">
        <template #default="scope">
           <el-link type="warning" @click="update(scope.row)">修改</el-link>
           <el-link type="danger" @click="del(scope.row.id)">删除</el-link>
        </template>
      </el-table-column>
     </el-table>

    <!-- 添加弹框 -->
    <el-dialog
      title="添加"
      :visible.sync="dialogVisible"
      width="30%">
      <el-form label-position="left" label-width="50px" :model="employee">
        <el-form-item label="id">
          <el-input v-model="employee.id"></el-input>
        </el-form-item>
        <el-form-item label="姓名">
          <el-input v-model="employee.name"></el-input>
        </el-form-item>
        <el-form-item label="地址">
          <el-input v-model="employee.address"></el-input>
        </el-form-item>
        <el-form-item label="性别">
          <el-radio v-model="employee.gender" label="1"></el-radio>
          <el-radio v-model="employee.gender" label="0"></el-radio>
        </el-form-item>
        <el-form-item label="部门">
          <el-select v-model="employee.department" placeholder="请选择">
            <el-option label="ABC" value="ABC"></el-option>
            <el-option label="AIDC" value="AIDC"></el-option>
        </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="add()">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 修改弹框 -->
    <el-dialog
      title="修改"
      :visible.sync="updateDialogVisible"
      width="30%">
      <el-form label-position="left" label-width="50px" :model="employee">
        <el-form-item label="id">
          <el-input v-model="employee.id"></el-input>
        </el-form-item>
        <el-form-item label="姓名">
          <el-input v-model="employee.name"></el-input>
        </el-form-item>
        <el-form-item label="地址">
          <el-input v-model="employee.address"></el-input>
        </el-form-item>
        <el-form-item label="性别">
          <el-radio v-model="employee.gender" label="1"></el-radio>
          <el-radio v-model="employee.gender" label="0"></el-radio>
        </el-form-item>
        <el-form-item label="部门">
          <el-select v-model="employee.department" placeholder="请选择">
            <el-option label="ABC" value="ABC"></el-option>
            <el-option label="AIDC" value="AIDC"></el-option>
        </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="updateDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="updateData()">确 定</el-button>
      </span>
    </el-dialog>

  </div>
</template>

<script type="text/javascript">
export default {
  name: "Task",
  data() {
    return {
      employee: {
        id: "",
        name: "",
        gender: "",
        address: "",
        email: "",
        phone: "",
        department: ""
      },
      empList:[],
      dialogVisible: false,
      updateDialogVisible: false
    }
  },
  mounted() {
    this.initData();
  },
  methods: {
    clearDara() {
      this.employee = {
        id: "",
        name: "",
        gender: "",
        address: "",
        email: "",
        phone: "",
        department: ""
      }
    },
    // 初始化
    initData() {
      this.getRequest("employee/query", this.employee).then(res=>{
        if(res.data.code == 0) {
          this.empList = res.data.info;
        }
      })
    },
    // 增加
    add() {
      this.postRequest("employee/add", this.employee).then(res=>{
        if(res.data.code == 0) {
          this.$message.success("添加成功!");
          this.initData();
        } else {
          this.$message.error("添加失败!" + res.data.msg);
        }
      })
      this.dialogVisible = false;
      this.clearDara();
    },
    // 更新
    update(emp) {
      this.employee = emp;
      this.updateDialogVisible = true;
    },
    updateData() {
      this.putRequest("employee/update", this.employee).then(res=>{
        if(res.data.code == 0) {
          this.$message.success("更新成功!");
          this.initData();
        }else {
          this.$message.error("更新失败!" + res.data.msg);
        }
      })
      this.updateDialogVisible = false;
      this.clearDara();
    },
    //删除
    del(id) {
      this.$alert('是否删除该记录', '提示', {
          confirmButtonText: '确定',
          callback: action => {
            this.deleteRequest("employee/delete/" + id).then(res=>{
            if(res.data.code == 0) {
              this.$message.success("删除成功!");
              this.initData();
            }else {
              this.$message.error("删除失败!" + res.data.msg);
            }
          })
          }
        });
    }
  }
}
</script>

<style scoped>
</style>

后端主要逻辑:

package com.controller;

import com.pojo.BaseResponse;
import com.pojo.Employee;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 10018318
 * 提供接口
 */
@RestController
@RequestMapping("/employee")
public class EmployeeController {
  private static final Map<Integer, Employee> employeeData = new LinkedHashMap<>();

  static {
    for (int num = 1001; num <= 1010; num++) {
      employeeData.put(num, new Employee(num, "李杰贵", "1", "lijiegui1@shein.com", "15874423919", "南京", "ABC"));
    }
  }

  /**
   * 查询员工信息
   */
  @GetMapping("/query")
  public BaseResponse getEmployeeList(Employee employee) {
    List<Employee> employeeList = employeeData.entrySet().stream()
        .filter(employeeEntry -> (StringUtils.isEmpty(employee.getName()) ? true : employeeEntry.getValue().getName().contains(employee.getName())) &&
            (StringUtils.isEmpty(employee.getGender()) ? true : employeeEntry.getValue().getGender().equals(employee.getGender())))
        .map(Map.Entry::getValue).collect(Collectors.toList());
    return BaseResponse.ok(employeeList);
  }

  /**
   * 添加职工
   * @param employee
   * @return
   */
  @PostMapping("/add")
  public BaseResponse addEmployee(@RequestBody Employee employee) {
    if (!employeeData.containsKey(employee.getId())) {
      employeeData.put(employee.getId(), employee);
      return BaseResponse.ok("添加成功!");
    }
    return BaseResponse.fail("添加失败,id已重复!");
  }

  /**
   * 删除职工
   * @param id
   * @return
   */
  @DeleteMapping("/delete/{id}")
  public BaseResponse delEmployeeById(@PathVariable Integer id) {
    employeeData.remove(id);
    if(!employeeData.containsKey(id)) {
      return BaseResponse.ok("删除成功!");
    }
    return BaseResponse.fail("删除失败!");
  }

  /**
   * 更新职工
   * @param employee
   * @return
   */
  @PutMapping("/update")
  public BaseResponse updateEmployee(@RequestBody Employee employee) {
    employeeData.put(employee.getId(), employee);
    return BaseResponse.ok("更新成功!");
  }
}

实体:

@Data
@AllArgsConstructor
public class Employee {
  private Integer id;

  private String name;

  private String gender;

  private String email;

  private String phone;

  private String address;

  private String department;
}

五、如何部署

npm run build

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PC7olzSj-1640781611641)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/eefefaa1-bbbf-4d20-908a-da9ad27980c1/Untitled.png)]

  • 部署方式:

    1、将dist文件下的内容复制到springboot工程下的resource下的static文件下

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kc4M2PJ0-1640781611642)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9dff1a66-fb61-464c-9b41-f4004aa14528/Untitled.png)]

    2、通过nginx代理实现,

    #user  nobody;
    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
    
        server {
        listen 80;
        server_name duxing.online;
    
        root  /home/duxing/front/dist/;
        index   index.html;
        try_files $uri $uri/ /index.html last;
    
            # gzip config
            gzip on;
            gzip_min_length 1k;
            gzip_comp_level 9;
            gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
            gzip_vary on;
            gzip_disable "MSIE [1-6]\.";
    
            location ^~ /prod-api/ {
                add_header 'Access-Control-Allow-Origin' *;
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
                proxy_pass http://127.0.0.1:8888/;
                proxy_set_header   X-Real-IP         $remote_addr;
                 proxy_set_header   Host              $http_host;
                 proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
            }
    	}
    	
    	server {
        listen 8085;
        server_name www.duxing.online;
    
        root  /home/duxing/back/dist/;
        index   index.html;
        try_files $uri $uri/ /index.html last;
    
            # gzip config
            gzip on;
            gzip_min_length 1k;
            gzip_comp_level 9;
            gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
            gzip_vary on;
            gzip_disable "MSIE [1-6]\.";
    
            location ^~ /prod-api/ {
                add_header 'Access-Control-Allow-Origin' *;
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
                proxy_pass http://127.0.0.1:8888/;
                proxy_set_header   X-Real-IP         $remote_addr;
                 proxy_set_header   Host              $http_host;
                 proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
            }
    	}
    }
    

参考:

https://cn.vuejs.org

https://juejin.cn/post/6844903709055401991

https://cn.vuejs.org/v2/guide/comparison.html