一、概述规划
01、基本的原型
02、准备工作
1、idea开发工具
2、Jdk1.8
3、Mysq5.7
4、SpringBoot + ssm(mybatis-plus)
5、Layui+Jquery
6、Vue2.6.12 + Axios
7、统计插件:echarts或antv
8、Navicat11
9、模板引擎:thymeleaf
10、git/gitee 牵涉的版本控制工具
03、架构
单体架构模式
04、2.0增加功能
二维码生成和扫码投票
05、表设计
数据脚本
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 60011
Source Host : localhost:3306
Source Database : ksd-state-db
Target Server Type : MYSQL
Target Server Version : 60011
File Encoding : 65001
Date: 2021-04-29 21:16:05
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for ksd_state
-- ----------------------------
DROP TABLE IF EXISTS `ksd_state`;
CREATE TABLE `ksd_state` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT NULL COMMENT '主题标题',
`description` varchar(600) DEFAULT NULL COMMENT '统计描述',
`personnum` int(11) DEFAULT NULL COMMENT '参与人数',
`endtime` varchar(30) DEFAULT NULL COMMENT '统计结束时间',
`status` int(1) DEFAULT NULL COMMENT '0未发布 1 发布',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT NULL,
`userid` int(11) DEFAULT NULL COMMENT '添加用户',
`username` varchar(100) DEFAULT NULL COMMENT '添加人的名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of ksd_state
-- ----------------------------
INSERT INTO `ksd_state` VALUES ('1', '飞哥', null, null, null, null, '2021-04-29 21:11:25', null, null, null);
-- ----------------------------
-- Table structure for ksd_state_detail
-- ----------------------------
DROP TABLE IF EXISTS `ksd_state_detail`;
CREATE TABLE `ksd_state_detail` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`title` varchar(100) DEFAULT NULL COMMENT '统计项的标题',
`status` int(1) DEFAULT NULL COMMENT '0未发布 1 发布',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT NULL,
`userid` int(11) DEFAULT NULL COMMENT '添加用户',
`username` varchar(100) DEFAULT NULL COMMENT '添加人的名称',
`itemnum` int(11) DEFAULT NULL COMMENT '具体项目点击数量',
`stateid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of ksd_state_detail
-- ----------------------------
INSERT INTO `ksd_state_detail` VALUES ('1', '小明', null, '2021-04-29 21:11:43', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('2', '小张', null, '2021-04-29 21:11:47', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('3', '小红', null, '2021-04-29 21:11:50', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('4', '小王', null, '2021-04-29 21:11:54', null, null, null, null, '1');
INSERT INTO `ksd_state_detail` VALUES ('5', '小李', null, '2021-04-29 21:11:56', null, null, null, null, '2');
-- ----------------------------
-- Table structure for ksd_state_user_detail
-- ----------------------------
DROP TABLE IF EXISTS `ksd_state_user_detail`;
CREATE TABLE `ksd_state_user_detail` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT NULL,
`userid` int(11) DEFAULT NULL COMMENT '添加用户',
`username` varchar(100) DEFAULT NULL COMMENT '添加人的名称',
`stateid` int(11) DEFAULT NULL,
`detailid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of ksd_state_user_detail
-- ----------------------------
INSERT INTO `ksd_state_user_detail` VALUES ('1', '2021-04-29 21:11:43', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('2', '2021-04-29 21:11:47', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('3', '2021-04-29 21:11:50', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('4', '2021-04-29 21:11:54', null, null, null, '1', null);
INSERT INTO `ksd_state_user_detail` VALUES ('5', '2021-04-29 21:11:56', null, null, null, '2', null);
06、echarts官网
07、效果展示
二、项目实战 - SpringBoot结合Vue2.x群统计项目-项目的搭建
01、课程目标
1、快速搭建springboot的SSM项目
2、在pom.xml中依赖SSM相关依赖
3、在application.yml中整合项目中常见配置
4、定义产品相关的entity、mapper、service、controller
5、完成统计业务的分数据库以及表的创建 分别是:统计表和统计明细表
6、定义一个页面index.html看是否能进行跳转
7、导入layui/jquery/vue/axios静态资源到static目录下
8、定义视图页面index.html设计添加投票的添加和查询统计
9、定义统计明细的接口以及使用vue进行渲染。
10、优化和完善
02、实现步骤
02-1、新建一个springboot工程
02-2、pom.xml引入支付相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mysql5.6x 驱动5.1.10-->
<!--mysql5.7x+ 驱动8.0.17-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
<!--二维码生成zxing-->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-avro</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
02-02、定义application.yml和application-prod.yml及application-dev.yml
server:
port: 80
# 数据库连接
spring:
application:
name: weixinpay
profiles:
active: dev
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
locale: zh_CN
# 解决json返回过程中long的精度丢失问题
generator:
write-numbers-as-strings: true
write-bigdecimal-as-plain: true
mvc:
servlet:
load-on-startup: 1 #SpringBoot的接口第一次访问都很慢,通过日志可以发现,dispatcherServlet不是一开始就加载的,有访问才开始加载的,即懒加载。
main:
allow-bean-definition-overriding: true
# mybatis-plus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:/mapper/*.xml
type-aliases-package: com.kuangstudy.entity
logging:
level:
root: info
# 微信登录相关
weixin:
login:
info:
# 微信小程序APPID
appid: wx2f823cdc8dfba815
# 微信小程序API私钥
appsecret: 0139a6d9e93fb88d3d68e0a8a1b06bd6
# 微信小程序登录成功回调地址
redirectUrl: https://www.kuangstudy.com/login/api/wx/callback
pay:
info:
# 微信支付网关
gateway: https://api.weixin.qq.com/sns/jscode2session
# 微信支付API秘钥
appsecret: 0139a6d9e93fb88d3d68e0a8a1b06bd6
# 微信商户id
mchid: 1550648501
# 微信小程序APPID
appid: wx2f823cdc8dfba815
# 支付成功回调地址,如果是微信小程序可以不配置
notifyPath: https://api.kuangstudy.com/api/pay/callback
application-prod.yml
server:
port: 80
# 数据库连接
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jiangfujiajiu?serverTimezone=GMT%2b8&useUnicode=true&characterEncoding=utf-8&useSSL=false
username: jiangfujiajiu
password: KiD2y5kDmZZEmc3p
hikari:
connection-timeout: 60000
validation-timeout: 3000
idle-timeout: 60000
login-timeout: 5
max-lifetime: 60000
maximum-pool-size: 400
minimum-idle: 100
read-only: false
application-dev.yml
# 数据库连接
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/jiangfujiajiu?serverTimezone=GMT%2b8&useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
hikari:
connection-timeout: 60000
validation-timeout: 3000
idle-timeout: 60000
login-timeout: 5
max-lifetime: 60000
maximum-pool-size: 400
minimum-idle: 100
read-only: false
02-4、定义产品相关的entity、mapper、service、controller
因为代码体积过大,详看源代码中的 相关文件
里有所有完整的源代码。请结合视频酌情复制即可。节约学习时间
源码下载地址:下载 - KuangStudy
02-5、完成产品列表接口的定义和查询
因为代码体积过大,详看源代码中的 相关文件
里有所有完整的源代码。请结合视频酌情复制即可。节约学习时间
源码下载地址:下载 - KuangStudy
02-6、完成产品明细接口的查询
因为代码体积过大,详看源代码中的
相关文件
里有所有完整的源代码。请结合视频酌情复制即可。节约学习时间
源码下载地址:下载 - KuangStudy
三、项目实战 - SpringBoot结合Vue2.x群统计项目-完成接口的对接和静态资源的导入
01、目标
完成接口的对接和静态资源的导入
02、具体实现
下载静态资源
1: 在任意磁盘新建一个文件夹
2:执行如下命令把对应项目以来的js组件和css组件全部下载下来
npm init -y
npm instaill vue jquery layui axios
npm install vue axios [email protected]
3、在各种的目录中找到/dist/编译好的对应组件的js和css即可,放入到项目的static/js/css/
03、热加载
1: 在settings的配置中找到自动编译
2: 在idea的注册列表中去打开另外一个自动编译的配置如下:
按快捷键:CTRL+SHIFT+ALT+/
3:在pom.xml文件中增加devtools的配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--fork:如果没有该项配置,整个devtools不会起作用-->
<fork>true</fork>
</configuration>
</plugin>
<plugin><!--编译跳过测试文件检查的生命周期-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
使用方式
在修改页面按N次ctrl+F9 会自动重新编译页面到target/classes/static目录, 请注意:这是不万能,所有如果没有效果,可以收到吧static静态资源或者template静态资源手动复制到target/classes/static
如果刷新没有看到效果:请用ctrl+f5 强刷N次
四、基于Vue搭建自身后台
01、具备的知识点
vue、vuex、vue-router
02、官网文档
vue:Vue.jsVue.js - The Progressive JavaScript Frameworkhttps://cn.vuejs.org/index.html
vue-router:Vue Routerhttps://router.vuejs.org/zh/
vuex:Vuex 是什么? | Vuexhttps://vuex.vuejs.org/zh/
03、如何搭建一个vue后台的项目
3-1、使用vue-cli快速构建一个后台
参考官网:Vue CLIhttps://cli.vuejs.org/zh/
前提
必须要安装nodejs
下载 | Node.js 中文网http://nodejs.cn/download/判断是否安装成功
node -v
安装
cnpm install -g @vue/cli
# OR
yarn global add @vue/cli(建议使用这个)
判断是否安装成功:
vue --version
启动项目
你可以通过vue ui命令图形化界面创建和管理项目,在项目所在目录进行cmd
vue ui
创建项目
创建完成会得到以下目录结构
3-2、安装核心的依赖
1、开发工具
vscode、webstorm、hbuilderx、idea
2、安装vuex和vue-router依赖
安装完成多了这两处
也可以使用命令进行安装
npm i vue-router vuex --save-dev
3、为什么要安装vuex和vue-router依赖
vuex:是状态管理的插件(有种session的感觉)
vue-router:是路由管理的插件
4、编写登录的页面和首页页面
(1)编写Login.vue页面组件,并且配置路由
<template>
<div class="ksd-loginbox">
<h1>我是一个登录页面组件</h1>
</div>
</template>
<script>
export default {
name: 'Login',
components: {
}
}
</script>
<style>
</style>
在router--index.js中添加
{
path: '/login',
name: 'Login',
component: () => import('../views/Login.vue')
},
原型链
原型链:是给所有的对象实例派生属性和方法的一种机制,也就是,给创建好的对象进行扩展方法和属性的一种机制,可以达到继承的目的。
main.js
function Player() { //相当于java中的class Player()
var name='' //成员变量
}
Player.age=10;//静态变量
//相当于对Player对象进行扩展
Player.prototype.play=function () {
console.log(111)
}
//相当于对Player对象进行扩展
Player.prototype.pause=function () {
console.log(222)
}
//每个对象都有自带的prototype
var player1 = new Player();
var player2 = new Player();
var player3 = new Player();
console.log(player1);
console.log(player2);
console.log(player3);
该如何使用呢?
main.js
//静态实例,若页面需要调用此实例,需要自己额外导入
Vue.sayHello2=function(){
alert("sayHello2")
}
//给每个页面都可以调用到sayHello实例
Vue.prototype.sayHello=function () {
console.log("sayHello")
}
Index.vue
<script>
import Vue from 'vue'; //静态实例调用sayHello需要额外导入
export default {
name: "Index",
components:{},
data(){
return{
}
},
created() {
this.sayHello();
//this.sayHello2();此处就需要导入
Vue.sayHello2();//上面进行了import Vue from 'vue';的导入
},
methods:{
}
}
</script>
所以this.$router就是
//所以this.$router就是
Vue.prototype.$router=function () {
return{
push:function () {}
}
}
进行页面跳转
<template>
<div class="ksd-loginbox">
<p>
<button @click="tologin">登录</button>
</p>
</div>
</template>
<script>
import loginService from "@/service/LoginService";
export default {
name: 'Login',
components: {
},
methods:{
tologin(){
//方法1:路径跳转
//this.$router.push('/');
//方法2:name跳转
// this.$router.push({'name':'Index'})
//方法3:可以抽离出来在进行定义跳转
loginService.login();
}
}
}
</script>
LoginService.js
import router from '@/router'
export default {
login(){
router.push("/");
}
};
(2)编写一个index.vue首页的组件,并且配置路由
下载插件vue-cli-plugin-element
发现项目中自动出现
之后就可以在element官网拿取样式(网址:Element - The world's most popular Vue UI framework )
此时出现一个问题:普通路由跳转会跳转到另外页面,不能实现只替换main中的内容
查询vue-router官网,使用嵌套路由进行实现(嵌套路由 | Vue Router)
{
path: '/user',
component: Index,
children:[
{
path: 'add',
name: 'UserAdd',
component: () => import('../views/user/Add.vue')
},
{
path: 'list',
name: 'UserList',
component: () => import('../views/user/List.vue')
}
]
}
Index.vue中添加<router-view></router-view>
<el-main>
<router-view></router-view>
</el-main>
(3)使用axios异步请求,模拟登录到index.vue(牵涉到知识点:axios和vue-router如何跳转,如果跳转过程中传递参数又如何传递,又如何接收)
axios官网:axios中文文档|axios中文网 | axios
axios是一个异步请求的js库,类似于:jquery异步
注意:无论是jquery异步,还是axios还是微信小程序:wx.request、ui.request都是对js中XMLHttpServletRequest的封装。
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应(异步的权限拦截 若依,antd,vue-admin)
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
把axios进行了一个重构和二次封装 request.js和server.js和cache.js
在图形化界面安装vue-cli-plugin-axios
安装完成后出现了一个报错
解决方法
打开package.json,在rules下添加
"no-unused-vars": "off"
如下图
然后重启项目
报错原因
项目安装了eslint校验,
后台
a、编写接口StateController
@GetMapping("/state/list")
public R findStates() {
QueryWrapper<State> queryWrapper = new QueryWrapper<>();
return R.ok().data("statesData", stateService.list(queryWrapper));
}
b、拦截器配置WebMvcConfig
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/state/**")
.allowedOrigins("http://localhost:8080") //此处如果写*,代表放行所有
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.maxAge(3600)
.allowedHeaders("*");
}
前端:
Index.vue
引入
import axios from 'axios';
<template>
<el-container>
<el-header>
<Nav></Nav>
</el-header>
<el-container>
<el-aside width="200px">
<Aside></Aside>
</el-aside>
<el-main>
<ul id="example">
<li v-for="item in statesData" :key="item.id">
{
{ item.id }}
{
{ item.title }}
{
{ item.createTime }}
</li>
</ul>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
// import Vue from 'vue';
import Nav from "../components/Nav";
import Aside from "../components/Aside";
//引入axios
import axios from 'axios';
export default {
name: "Index",
components: {
Nav, Aside
},
data() {
return {
data:{},
statesData:[] //获取数组
}
},
created() {
var promise = axios.get("http://localhost/state/list");
promise.then(res=>{
this.data=res.data.data
this.statesData=res.data.data.statesData
console.log("res",res)
}).catch(error=>{
console.log("error",error)
})
},
methods: {}
}
</script>
(4)、了解一个页面的组成部分,以及了解axios异步处理框架(异步自定义、拦截器)对照若依或者antd源码进行分析
axios
1、异步处理肯定是每个开发人员都要调用的js库,因为要完成数据接口渲染工作。开发定义的位置和业务是非常多的,一旦维护起来会非常的不方便
2、书写方式不友好,后续的优化和控制就不便
3、如果接口一旦要考虑安全性jwt token,那么每个axios处理接口的地方都需要增加参数或者请求头中增加参数,导致后续不便
4、在开发中axios有些请求是需要拦截的,有些是不需要拦截,如何进行封装和重构,就很有必要
5、在肯定要增加一些统一域名和统一参数或者一些状态标志等等,如果每个地方去增加也不方便
封装思路:
1、entity、service、controller
2、接口--后端提供--entity
3、接口--axios--service--页面(页面组件)
封装的好处
复用
配置项目所需要的服务常量
(5)封装一个request.js来完成异步请求的逻辑
此处拦截器代码还未实现
import server from '../common/server';
import axios from 'axios'
var request=function (url,params,type="get") {
var token='xxxxxx';
var headers={'token': token}
var requestparams={};
if (type && type.toUpperCase() == 'post') {
headers["content-type"] = "application/x-www-form-urlencoded";
requestparams=params;
}else {
requestparams.params=params;
}
//1:创建一个axios的对象,对异步请求对象进行增强的处理
const axiosInstance=axios.create({
//如果你访问的路径是一个相对路径,就自动增加baseURL,
//如果你访问是一个https或者http请求就不会增加baseURL
baseURL:server.url,
headers:headers
});
// 添加请求拦截器
axiosInstance.interceptors.request.use(function (config) {
console.log("拦截器。。。。")
console.log(config)
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axiosInstance.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
return axiosInstance[type](url,requestparams);
}
//注意:凡是可以.的都是对象,对象.属性 或者对象[属性]
// var request = function (url, params, type) {
//
// //1、处理token,放入到请求头中
// var token = "xxxxxx";
// var headers = {'token': token}
//
// //3、组装异步请求的参数
// var axiosobj = {
// method: type || "get",
// url: server.url + url,
// // data: params,
// headers
// };
//
// //2、处理post请求参数的问题
// if (type && type.toUpperCase() == 'post') {
// headers["content-type"] = "application/x-www-form-urlencoded";
// axiosobj.data=params;
// }else{
// axiosobj.params=params;
// }
//
// //返回参数
// return axios(axiosobj);
// };
//
export default request;
(6)开始对项目进行分层框架和目录划分,让业务和接口调用进行分离
像后台分层一样进行划分
(7)安装一个elementui组件(布局使用,路由完成跳转)
制作组件
Aside组件(类似于侧边导航栏)
<template>
<el-menu
default-active="1"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
background-color="#545c64"
text-color="#fff"
style="height: 100%"
active-text-color="#ffd04b">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span>首页后台</span>
</template>
<el-menu-item-group>
<el-menu-item index="1-1">
<router-link to="/user/list">用户管理</router-link>
</el-menu-item>
<el-menu-item index="1-2">
<router-link to="/user/add">用户添加</router-link>
</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">订单管理</span>
</el-menu-item>
<el-menu-item index="3">
<i class="el-icon-document"></i>
<span slot="title">课程管理</span>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<span slot="title">系统设置</span>
</el-menu-item>
</el-menu>
</template>
<script>
export default {
name: "Aside",
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
}
</script>
<style scoped>
</style>
在vue页面中引入组件<Aside></Aside>
<template>
<el-container>
<el-header>
<Nav></Nav>
</el-header>
<el-container>
<el-aside width="200px">
<Aside></Aside>
</el-aside>
<el-main>
<ul id="example">
<li v-for="item in statesData" :key="item.id">
{
{ item.id }}
{
{ item.title }}
{
{ item.createTime }}
</li>
</ul>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
import Nav from "../components/Nav";
import Aside from "../components/Aside";
import stateService from "../service/state/StateService";
import stateDetailService from "../service/index/IndexService"
import toLogin from "../common/login";
export default {
name: "Index",
components: {
Nav, Aside
},
data() {
return {
data:{},
statesData:[] //获取数组
}
},
created() {
var promise = stateService.getState();
promise.then(res=>{
this.data=res.data.data
this.statesData=res.data.data.statesData
console.log("res",res)
}).catch(error=>{
console.log("error",error)
})
},
methods: {
//加载明细
loadStateDetail(){
toLogin(function () {
stateDetailService.getStateDetail().then(res=>{
console.log(res)
}).catch(err=>{
console.log("error",err)
})
})
}
}
}
</script>
<style scoped>
</style>
(8)状态管理的module的分析和业务的结合。(为代码实现:登录放入vuex进行管理,然后在首页中展示用户信息)
项目实战 - SpringBoot结合Vue2.x群统计项目-统计页面的展示和数据查询检索
01、目标
统计页面的展示和数据查询检索
02、具体实现
1、官网:Layui 开发使用文档 - 入门指南
2、下载
npm i layui
Vue组件通信 - 父子之间通信 - $parent 和 $refs
01、目标
使用$parent完成子调用父组件的方法和属性
02、具体实现
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
{ {title} }
<mybutton v-bind:message="title"></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
// 子调用父的函数----调用函数
const buttonCompoment= {
template:"<button @click='childrenClick'>{ {message} }</button>",
// 它的数据是一个函数 + return {}。
data(){
return {
name:"按钮1"
}
},
// 生命周期钩子
created(){
console.log("组件加载完毕执行此处...")
},
// 组件属性 自定义属性
props : {
"message":{type:String}
},
// 计算属性
computed : {
},
// 方法
methods : {
childrenClick(){
// 调用父属性
this.$parent.title = "子改变父亲的标题了哦!!";
// 调用父函数
this.$parent.calnum();
}
},
// 监控属性
watch : {
}
}
// 全局注册
Vue.component("mybutton",buttonCompoment);
// 1 : 实例化vue
var vue = new Vue({
// 2 : 指定渲染的范围
el:"#app",
// 3 :数据定义的位置也就是Model
data:{
title:"我是的标题"
},
// 4: 事件定义的位置,@事件类型="事件名"
methods:{
calnum(){
alert("我调用父亲的函数");
}
}
})
</script>
</body>
</html>
Vue高级编程 - 组件
官网参考:组件基础 — Vue.js
01、概述
在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。但是如果每个页面都独自开发,这无疑增加了开发的成本。所以会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
Vue组件的作用: 复用
通常一个应用会以一棵嵌套的组件树的形式来组织:
02、目标
定义和注册组件
03、定义组件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<mybutton></mybutton>
<mybutton></mybutton>
<mybutton></mybutton>
<mybutton></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
// 自定义组件
const buttonCompoment= {
// 这里是组件的模板
template:"<button>{ {name} }</button>",
// 它的数据是一个函数 + return {}。
data(){
return {
name:"按钮1"
}
},
// 生命周期钩子
created(){
console.log("组件加载完毕执行此处...")
},
// 组件属性
props : {
},
// 计算属性
computed : {
},
// 方法
methods : {
},
// 监控属性
watch : {
}
}
// 1 : 实例化vue
var vue = new Vue({
// 2 : 指定渲染的范围
el:"#app",
// 3 :数据定义的位置也就是Model
data:{
},
// 4: 事件定义的位置,@事件类型="事件名"
methods:{
}
})
</script>
</body>
</html>
04、小结
组件中的data是一个json对象?
不是,必须是一个函数。这个是和父组件的区别
Vue高级编程 - 组件注册
官网参考:组件基础 — Vue.js
01、目标
组件的注册(全局注册和局部注册)
02、全局注册
- 全局注册的组件,可以用在所有的 Vue 实例 (
new Vue
) 中。 - 语法如下
# 第一种方式
Vue.component('组件名称', { /* ... */ })
# 第二种方式
Vue.component('组件名称', 组件对象);
- 定义组件名
参考官网:组件注册 — Vue.js
03、全局注册具体实现
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
{ {title} }
<mybutton></mybutton>
<mybutton></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
// 自定义组件
const buttonCompoment= {
template:"<button>{ {name} }</button>",
// 它的数据是一个函数 + return {}。
data(){
return {
name:"按钮1"
}
},
// 生命周期钩子
created(){
console.log("组件加载完毕执行此处...")
},
// 组件属性 自定义属性
props : {
},
// 计算属性
computed : {
},
// 方法
methods : {
},
// 监控属性
watch : {
}
}
// 全局注册
Vue.component("mybutton",buttonCompoment);
// 1 : 实例化vue
var vue = new Vue({
// 2 : 指定渲染的范围
el:"#app",
// 3 :数据定义的位置也就是Model
data:{
title:"我是一个按钮"
},
// 4: 事件定义的位置,@事件类型="事件名"
methods:{
}
})
</script>
</body>
</html>
04、局部注册组件
- 局部注册的组件,只能在当前的Vue实例中可以使用
- 语法
// 局部注册组件(只有当前vue实例可以用)
components : {
"mybutton" : MyButton
}
- 使用自定义组件:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
{ {title} }
<mybutton></mybutton>
<mybutton></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
// 自定义组件
const buttonCompoment= {
template:"<button>{ {name} }</button>",
// 它的数据是一个函数 + return {}。
data(){
return {
name:"按钮1"
}
},
// 生命周期钩子
created(){
console.log("组件加载完毕执行此处...")
},
// 组件属性 自定义属性
props : {
},
// 计算属性
computed : {
},
// 方法
methods : {
},
// 监控属性
watch : {
}
}
// 全局注册
//Vue.component("mybutton",buttonCompoment);
// 1 : 实例化vue
var vue = new Vue({
// 2 : 指定渲染的范围
el:"#app",
// 3 :数据定义的位置也就是Model
data:{
title:"我是一个按钮"
},
// 4: 事件定义的位置,@事件类型="事件名"
methods:{
},
//局部注册
components:{
"mybutton":buttonCompoment
}
})
</script>
</body>
</html>
05、小结
- 全局注册组件与局部注册组件的区别?
全局可以提供给所有页面使用,局部只能给当前页面使用。
- 全局注册组件语法?
// 全局注册
Vue.component("mybutton",buttonCompoment);
Vue高级编程 - 组件-父向子通讯-Props
官网参考:Prop — Vue.js
01、目标
通过 Prop 向子组件传递数据
02、语法
// 定义组件: 组件属性(定义父组件需要传递过来的属性)
props : {
// Prop属性名 : {type : "数据类型", required : 是否必须}
title : {type : String, required : true},
color : {type : String, required : false}
}
// 使用组件
<组件名称 title="" color=""></组件名称>
03、具体代码
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<mybutton v-bind:message="title"></mybutton>
<mybutton v-bind:message="title"></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
// 子调用父的函数----调用函数
const buttonCompoment= {
template:"<button>{ {message} }</button>",
// 它的数据是一个函数 + return {}。
data(){
return {
name:"按钮1"
}
},
// 生命周期钩子
created(){
console.log("组件加载完毕执行此处...")
},
// 组件属性 自定义属性
props : {
"message":{type:String}
},
// 计算属性
computed : {
},
// 方法
methods : {
},
// 监控属性
watch : {
}
}
// 全局注册
Vue.component("mybutton",buttonCompoment);
// 1 : 实例化vue
var vue = new Vue({
// 2 : 指定渲染的范围
el:"#app",
// 3 :数据定义的位置也就是Model
data:{
title:"我是的父按钮"
},
// 4: 事件定义的位置,@事件类型="事件名"
methods:{
}
})
</script>
</body>
</html>
04、小结
父组件如何与子组件通信? props
Vue高级编程 - 组件- 子向父通信 - $emit
参考官网:自定义事件 — Vue.js
01、目标
通过Vue实例$emit方法,触发当前实例上的事件方式向父组件传递数据
02、具体实现
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<mybutton @btnclick="calcNum"></mybutton>
<mybutton @btnclick="calcNum"></mybutton>
</div>
<script src="js/vue.min.js"></script>
<script>
// 子调用父的函数----调用函数
const buttonCompoment= {
template:"<button @click='clickme'>{ {name} }</button>",
// 它的数据是一个函数 + return {}。
data(){
return {
name:"点击调用父元素方法"
}
},
// 生命周期钩子
created(){
console.log("组件加载完毕执行此处...")
},
// 组件属性 自定义属性
props : {
},
// 计算属性
computed : {
},
// 方法
methods : {
clickme(){
//这里是自定义事件,参数1是事件名称,参数2是参数
this.$emit("btnclick",{});
}
},
// 监控属性
watch : {
}
}
// 全局注册
Vue.component("mybutton",buttonCompoment);
// 1 : 实例化vue
var vue = new Vue({
// 2 : 指定渲染的范围
el:"#app",
// 3 :数据定义的位置也就是Model
data:{
title:"我是的标题"
},
// 4: 事件定义的位置,@事件类型="事件名"
methods:{
calcNum(){
alert("你调用父函数...")
}
}
})
</script>
</body>
</html>
03、小结
子组件如果向父组件通信? $emit
视频地址:项目实战 - SpringBoot结合Vue2.x群统计项目_哔哩哔哩_bilibili
本地mysql数据库:kuangstudy
项目位置:F:\studyitems\开源项目\vue2结合springboot群统计项目\Mytry