java从入门到精通二十五(vue和element 对项目的改进)
- vue
- 常见的vue指令
- 生命周期
- vue对项目前端的优化
- Element
- 页面设计
- Servlet 代码功能优化
vue
我们之前获取前端表单数据的时候,我们需要进行大量的操作。当前我只是进行了浅显的一些认识。
我们用vue可以实现的是一种数据双向绑定的操作。 我们之前实现的mvc的思想只能实现模型到视图的单向展示。不能够实现双向。也就是视图到模型是不可以的。
我们可以认为这样是数据模型和视图的结合。for遍历模型数据,然后取出数据在页面上展示。但是,我们我们不能反着来,我们把视图的数据绑定到模型里面。所以我们需要用到vue这个框架。
图中的 就是我们的数据, View 是视图,也就是页面标签,用户可以通过浏览器看到的内容; Model 和View 是通 对象进行双向绑定的,而ViewModel对象是Vue来实现提供。
Vue 框架很核心的功能就是双向的数据绑定。 双向是指:HTML 标签数据 绑定到 Vue 对象,另外反方向数据也是绑定的。通俗点说就是,Vue 对象的改变会直接影响到 HTML 的标签的变化,而且标签的变化也会反过来影响 Vue 对象的属性的变化。 这样以来,就彻底变革了之前 Dom 的开发方式,之前 Dom 驱动的开发方式尤其是以 jQuery 为主的开发时代,都是 dom 变化后,触发 js 事件,然后在事件中通过 js 代码取得标签的变化,再跟后台进行交互,然后根据后台返回的结果再更新 HTML 标签,异常的繁琐。有了 Vue 这种双向绑定,让开发人员只需要关心 json 数据的变化即可,Vue 自动映射到 HTML 上,而且 HTML 的变化也会映射回 js 对象上,开发方式直接变革成了前端由数据驱动的 开发时代,远远抛弃了 Dom 开发主导的时代了。 ———————————————— 该段描述源自,非常清晰。让你明白vue到底干了什么事情。 版权声明:本文为CSDN博主「w_t_y_y」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/w_t_y_y/article/details/107785261
在做任何事情上,都需要先来了解其基本的思想,解决方案。
我们看一段简单的代码。说明一下执行流程。
来看一段代码
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input v-model="username">
<!--插值表达式-->
{{username}}
</div>
<script src="js/vue.js"></script>
<script type="application/javascript">
//1. 创建Vue核心对象
new Vue({
el:"#app",
data(){
return {
username:"888"
}
}
/*data: function () {
return {
username:""
}
}*/
});
</script>
</body>
</html>
我们展开页面。默认数据会是888。
首先我们框框里面的内容可以认为是前端页面,我们的vue里面的内容自动映射到了,然后如果我们在这里输入,也可以获取到值。
所以其实就是按照这个原理实现了数据的双向绑定。
用户在视图上的修改会自动同步到数据模型中去,同样的,如果数据模型中的值发生了变化,也会立刻同步到视图中去。双向数据绑定的优点是无需进行和单向数据绑定的那CRUD(Create,Retrieve,Update,Delete)操作双向数据绑定最经常的应用场景就是表单了,这样当用户在前端页面完成输入后,不用任何操作,我们就已经拿到了用户的数据存放到数据模型中了。
我们要使用vue的话,就需要去导入vue的文件。axios 用于将来我们发送异步请求。这些问价自行下载。
常见的vue指令
v-bind 为HTML标签绑定属性值,如设置 href , css样式等 v-model 在表单元素上创建双向数据绑定 v-on 为HTML标签绑定事件 v-if 条件性的渲染某元素,判定为true时渲染,否则不渲染 v-else v-else-if v-show 根据条件展示某元素,区别在于切换的是display属性的值 v-for 列表渲染,遍历容器的元素或者对象的属性 eg:
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<a v-bind:href="url">点击一下</a>
<a :href="url">点击一下</a>
<input v-model="url">
</div>
<script src="js/vue.js"></script>
<script>
//1. 创建Vue核心对象
new Vue({
el:"#app",
data(){
return {
username:"",
url:"https://www.baidu.com"
}
}
});
</script>
</body>
</html>
绑定事件
代码语言:javascript复制 <!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="button" value="一个按钮" v-on:click="show()"><br>
<input type="button" value="一个按钮" @click="show()">
</div>
<script src="js/vue.js"></script>
<script>
//1. 创建Vue核心对象
new Vue({
el:"#app",
data(){
return { username:"",
}
},
methods:{
show(){
alert("我被点了..."); }
}
});
</script>
</body>
</html>
v-for 指令,是对标签进行循环的操作。
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-for="addr in addrs">
{{addr}}<br>
</div>
<hr>
<div v-for="(addr,i) in addrs">
{{i 1}}--{{addr}}<br>
</div>
</div>
<script src="js/vue.js"></script>
<script>
new Vue({
el: "#app",
data() {
return {
addrs: ["大毛", "二毛", "三毛"]
}
}
});
</script>
</body>
</html>
v-if 指令
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-if="count==3">div1</div>
<div v-else-if="count==4">div2</div>
<div v-else>div3</div>
<hr>
<input v-model="count">
</div>
<script src="js/vue.js"></script>
<script>
new Vue(
{
el:"#app",
data()
{
return{
count:3
}
}
}
)
</script>
</body>
</html>
未完续更。
生命周期
我们后面在项目中用到的就是mounted这个生命周期,代表在挂载完成启动的。
了解一下就可以。 mounted :挂载完成,Vue初始化成功,HTML页面渲染成功。
vue对项目前端的优化
我们目前所做的优化就是针对前端页面进行修改。后端先不进行改动。 我们用vue框架。
在优化前端页面之前,我们先回顾下之前写的页面。
代码语言:javascript复制<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="css/login.css" rel="stylesheet">
<%-- <style>--%>
<%-- .box{--%>
<%-- width: 400px;--%>
<%-- height: 100px;--%>
<%-- text-align: center;--%>
<%-- }--%>
<%-- </style>--%>
</head>
<body>
<%--<h1>${user.username},欢迎您</h1>--%>
<input type="button" value="新增" id="add" style="margin-left: -100px;margin-top: -300px;color: #50afeb"><br>
<hr>
<%--<div class="box">${user.username},欢迎您</div>--%>
<table border="1" cellspacing="0" width="80%">
<caption align="top" >${user.username},欢迎您</caption>
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<c:forEach items="${brands}" var="brand" varStatus="status">
<tr align="center">
<%--<td>${brand.id}</td>--%>
<td>${status.count}</td>
<td>${brand.brandName}</td>
<td>${brand.companyName}</td>
<td>${brand.ordered}</td>
<td>${brand.description}</td>
<c:if test="${brand.status == 1}">
<td>启用</td>
</c:if>
<c:if test="${brand.status != 1}">
<td>禁用</td>
</c:if>
<td><a href="/brand-demo01/selectByIdServlet?id=${brand.id}">修改</a>
<a href="/brand-demo01/selectDeleteServlet?id=${brand.id}">删除</a></td>
</tr>
</c:forEach>
</table>
<script>
document.getElementById("add").onclick = function (){
location.href = "/brand-demo01/addBrand.jsp";
}
</script>
</body>
</html>
我们就看这个表单展示页面。 我们用到一个JSTL的 c标签来进行了对页面的简化操作。说实话,感觉还是挺好用的。我们使用vue的话,其实这里可以使用vue的v-for标签。
类似于这样
代码语言:javascript复制 <tr v-for="(brand,i) in brands" align="center"> 2 <td>{{i 1}}</td>
<td>{{brand.brandName}}</td>
<td>{{brand.companyName}}</td>
<td>{{brand.ordered}}</td>
<td>{{brand.description}}</td>
<td>{{brand.statusStr}}</td>
<td><a href="#">修改</a> <a href="#">删除</a></td> 9 </tr>
我们之前的页面,按照之前的逻辑,我们想要获取到brand对象的内容,我们需要先走这一步,就是查询所有的Servlet,然后这个Servlet将对象存入request域当中。然后在jsp里面就可以得到了。
我们用vue加上axios来进行数据模型来进行操作。 其实可以按照异步请求加上数据模型。 eg:
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<a href="addBrand.html"><input type="button" value="新增"></a><br>
<hr>
<table id="brandTable" border="1" cellspacing="0" width="100%">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<!--
使用v-for遍历tr
-->
<tr v-for="(brand,i) in brands" align="center">
<td>{{i 1}}</td>
<td>{{brand.brandName}}</td>
<td>{{brand.companyName}}</td>
<td>{{brand.ordered}}</td>
<td>{{brand.description}}</td>
<td>{{brand.statusStr}}</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<!--<tr align="center">
<td>2</td>
<td>优衣库</td>
<td>优衣库</td>
<td>10</td>
<td>优衣库,服适人生</td>
<td>禁用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td>3</td>
<td>小米</td>
<td>小米科技有限公司</td>
<td>1000</td>
<td>为发烧而生</td>
<td>启用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>-->
</table>
</div>
<script src="js/axios-0.18.0.js"></script>
<script src="js/vue.js"></script>
<script>
new Vue({
el: "#app",
data(){
return{
brands:[]
}
},
mounted(){
// 页面加载完成后,发送异步请求,查询数据
var _this = this;
axios({
method:"get",
url:"http://localhost:8080/brand-demo/selectAllServlet"
}).then(function (resp) {
_this.brands = resp.data;
})
}
})
/*//1. 当页面加载完成后,发送ajax请求
window.onload = function () {
//2. 发送ajax请求
axios({
method:"get",
url:"http://localhost:8080/brand-demo/selectAllServlet"
}).then(function (resp) {
//获取数据
let brands = resp.data;
let tableData = " <tr>n"
" <th>序号</th>n"
" <th>品牌名称</th>n"
" <th>企业名称</th>n"
" <th>排序</th>n"
" <th>品牌介绍</th>n"
" <th>状态</th>n"
" <th>操作</th>n"
" </tr>";
for (let i = 0; i < brands.length ; i ) {
let brand = brands[i];
tableData = "n"
" <tr align="center">n"
" <td>" (i 1) "</td>n"
" <td>" brand.brandName "</td>n"
" <td>" brand.companyName "</td>n"
" <td>" brand.ordered "</td>n"
" <td>" brand.description "</td>n"
" <td>" brand.status "</td>n"
"n"
" <td><a href="#">修改</a> <a href="#">删除</a></td>n"
" </tr>";
}
// 设置表格数据
document.getElementById("brandTable").innerHTML = tableData;
})
}*/
</script>
</body>
</html>
对的其他也可以按照这样的逻辑处理。但是其实还有一个问题就是这个页面太丑了。这个表单太丑了,是我我绝对不会访问这样的页面的。
那么我们还有什么办法呢?css?不,不用这个美化。我们用element。
Element
先给看一下我们最终完成的效果页面。当然功能已经全部改进了。并且做了一些修改。这个页面是非常漂亮的。
页面设计
需要使用到element-ui。
于是我们可以用element去改造页面。
首先是搜索表单
代码语言:javascript复制 <el-form :inline="true" :model="brand" class="demo-form-inline">
<el-form-item label="当前状态">
<el-select v-model="brand.status" placeholder="当前状态">
<el-option label="启用" value="1"></el-option>
<el-option label="禁用" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="企业名称">
<el-input v-model="brand.companyName" placeholder="企业名称"></el-input>
</el-form-item>
<el-form-item label="品牌名称">
<el-input v-model="brand.brandName" placeholder="品牌名称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
然后新增和删除两个按钮
代码语言:javascript复制 <el-row>
<el-button type="danger" plain @click="deleteByIds">批量删除</el-button>
<el-button type="primary" plain @click="dialogVisible01 = true">新增</el-button>
</el-row>
然后表格
代码语言:javascript复制 <template>
<el-table
:data="tableData"
style="width: 100%"
:row-class-name="tableRowClassName"
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column
type="index"
width="50">
</el-table-column>
<el-table-column
prop="brandName"
label="品牌名称"
align="center"
>
</el-table-column>
<el-table-column
prop="companyName"
label="企业名称"
align="center"
>
</el-table-column>
<el-table-column
prop="ordered"
align="center"
label="排序">
</el-table-column>
<el-table-column
prop="description"
align="center"
label="描述信息">
</el-table-column>
<el-table-column
align="center"
label="操作">
<template slot-scope="scope">
<el-row>
<!-- <el-button type="primary"@click="update" >修改</el-button>-->
<!-- 修改按钮 -->
<el-button type="primary" @click="showEditDialog(scope.row)">修改</el-button>
<el-button type="danger"@click="toDelete(scope.row)">删除</el-button>
</el-row>
</el-dialog>
</template>
</el-table-column>
</el-table>
</template>
然后分页工具条
代码语言:javascript复制 <!--分页工具条-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[5, 10, 15, 20]"
:page-size="5"
layout="total, sizes, prev, pager, next, jumper"
:total="totalCount">
</el-pagination>
这个时候我们可以先设计默认的数据。
我们在vue中设定一下。
我们先给定这样的数据。其实这样展示出来的就是静态界面。
下面我们完成各个功能。在这之前,我们对Servlet进行一些优化。
Servlet 代码功能优化
按照我们之前的话,几乎每一个功能都需要写一个Servlet,这样看着真的很麻烦。我们该如何优化呢?
之前我们写每个功能都需要写这个。
现在我们不这样写了,我们写一个类。 我们知道我们服务器启动我调用service。我们可以从这里入手。
代码语言:javascript复制package com.jgdabc.web.servlet;
//替换HttpServlet,根据请求的最后一段路径来进行方法分发
import com.jgdabc.service.BrandService01;
import com.jgdabc.service.impl.BrandServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class BaseServlet extends HttpServlet {
// 根据请求的最后一段路径来进行方法分发
// 获取请求路径
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.service(req, resp);
// 获取请求路径
String uri = req.getRequestURI();
System.out.println(uri);
int index = uri.lastIndexOf('/');
System.out.println(index);
String methodName = uri.substring(index 1);
System.out.println(methodName);
// 执行方法
// 获取BrandServlet/UserServlet 字节码对象
// 获取方法的method对象
// this 代表谁调用我我代表谁(看service被谁调用)
System.out.println(this);
Class<? extends BaseServlet> cls = this.getClass();
try {
Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// 执行方法
}
}
我们这个涉及还用到了反射的知识。这样是非常巧妙的设计为什么巧妙?请继续看。 然后我们再设计一个类。我们先简单写一部分查询的功能。
代码语言:javascript复制package com.jgdabc.web.servlet;
import com.alibaba.fastjson.JSON;
import com.jgdabc.pojo.Brand;
import com.jgdabc.pojo.PageBean;
import com.jgdabc.service.BrandService01;
import com.jgdabc.service.impl.BrandServiceImpl;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;
@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet {
private BrandService01 brandService01 = new BrandServiceImpl();
public void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("brand selectAll");
List<Brand> brands = brandService01.selectAll();
// 转为json
String jsonString = JSON.toJSONString(brands);
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(jsonString);
}
}
看我们之前的servlet的写法
我们之前怎么访问的?我们之前当我们需要查询的功能的时候,我们是直接访问这个资源路径,然后在这里面获取到处理逻辑。查询是一个,那么添加修改也是这样的逻辑。但是现在我们让资源路径统一一部分。什么意思,我采用的是servlet访问路径都一样,只不过这个这里面也是可以实现不同的功能。如何实现不同的功能。我们在里面定义不同的方法。
服务器启动,前端异步请求发出,我们的BaseServle里面的service启动执行,然后获取到url,经过中间处理,我们可以获取到完整的方法名。还有this这个关键字你需要注意它的巧妙用法。
这个this 指代什么?
谁调用它它就指代哪个对象。
在这里指代 com.jgdabc.web.servlet.BrandServlet@f53487 那么我们可以去通过这个this来进行反射来调用到对应的方法就行执行。
原理就是这样。逻辑思维就是这样。
我们之后的功能都是基于这个来实现。那样以后我们按照这个优化只需要创建两个Servlet。当前除去工具类。我们这样可以大大缩减工作量。
未完,续更。