【Web实战-Tomcat-Servlet-Thymeleaf -JDBC-MySQL】浏览器页面显示数据库数据(水果库存系统)

news2025/7/19 6:35:04

🥇作者 .29. 的✔博客主页✔
🥇记录JavaWeb学习的专栏:Web专栏
🥇拼搏起来吧,未来会给你开出一个无法拒绝的条件…

您的点赞收藏以及关注是对作者最大的鼓励喔 ~~

在这里插入图片描述

在这里插入图片描述

客户端展示库存数据

  • 前言
  • 一、Thymeleaf - 视图模板技术
    • 1.导入 jar 包
    • 2.创建Servlet类,设置相关属性与方法。
    • 3.添加web.xml文件配置
    • 4.使用Thymeleaf技术相关的HTML标签属性
  • 二、浏览器页面实现
    • 1.获取数据库数据
    • 2.使用Servlet组件渲染页面
      • ①`Servlet组件`
      • ②`HTML页面`
  • 三、效果
  • 总结


前言

在JDBC专栏中,我们完成了水果库存系统功能的设计,实现以及优化,但总得来看,整个项目都是后端的代码,系统的页面也不过是通过控制台模拟而来的,而非真正的前端页面。

而在这篇文章开始,我们会对水果库存系统的客户端页面功能进行设计与实现,让库存系统可以在网页中使用。

项目中我们主要依赖Tomcat部署,使用Servlet组件,过程中通过JDBC连接MySQL数据库获取数据,将数据在浏览器页面中展现出来。


一、Thymeleaf - 视图模板技术

在开始,我们需要先了解一下Thymeleaf - 视图模板技术的使用,这是我们在使用Servlet时需要用到的技术。

接下来,我们通过 Thymeleaf 的使用来了解视图模板技术到底是什么。

1.导入 jar 包

需要使用Thymeleaf - 视图模板技术,第一步就是导入相关的 jar 包了,具体的步骤大家应该都了解,不了解的可以按照这篇文章的思路来尝试导入jar包:druid数据库连接池的使用。

Thymeleaf - 视图模板技术 jar包资源:
链接:https://pan.baidu.com/s/1NOucl2A8nEAIzg-rT4GqGg
提取码:leaf


2.创建Servlet类,设置相关属性与方法。

我们需要创建一个Servlet类,我将这个类命名为ViewBaseServlet,说其是Servlet类是因为它需要继承HttpServlet类
ViewBaseServlet类中设置的是与使用Thymeleaf 技术相关的属性以及方法,我们可以通过代码来了解其功能:

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

3.添加web.xml文件配置

web.xml文件是一个Web项目的配置文件.

上文提到的ViewBaseServlet类代码中,有两个重要的部分:

  • 添加前缀 view-prefix
  • 添加后缀 view-suffix

除了ViewBaseServlet类,我们还需要在web.xml文件中添加前缀与后缀相关的参数配置,参数配置代码如下:

    <context-param>
        <param-name>view-prefix</param-name>
        <param-value>/</param-value>
    </context-param>
    <context-param>
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>

参数配置中,我们将前缀设置为/;同时后缀设置为.html

这样的用意在于我们可以使用Thymeleaf - 视图模板技术,通过逻辑视图名称获取到对应的物理视图名称,例如:

//假设此时的视图名称是index
//那么Thymeleaf会将这个 逻辑视图名称 对应到 物理视图名称上去
//逻辑视图名称 : index
//物理视图名称 : view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是 / + index + .html

我们先了解一下使用的效果即可,至于为什么这样,我们会在后续代码的实现中体现出来。


4.使用Thymeleaf技术相关的HTML标签属性

在HTML中,需要使用Thymeleaf技术,我们需要在html标签中添加相关属性:

<html xmlns:th="http://www.thymeleaf.org">
</html>

而后,当我们使用Thymeleaf技术的属性时,都需要在属性前添加th:的标志。



二、浏览器页面实现

1.获取数据库数据

我们需要在浏览器页面中显示数据库中存放的数据,那么我们就首先要连接数据库来获取数据,这时候正好就需要连接数据库执行更新或查询操作的功能。

相关功能的通用方法,已经在我们的JDBC专栏:JDBC实战系列文章中完成,直接拿过来使用即可:

BaseDAO类代码

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author .29.
 * @create 2022-09-25 19:30
 */
public abstract class BaseDAO<T> {
    public final String DRIVER = "com.mysql.cj.jdbc.Driver";
    public final String URL = "jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&CharacterEncoding=utf-8";
    public final String USER = "root" ;
    public final String PSW = "" ;

    protected Connection connection;
    protected PreparedStatement pstm;
    protected ResultSet rs;

    //获取T的对象
    private Class entityClass;

    //构造方法
    public BaseDAO(){
        //getClass() 获取Class对象,我们当前创建的是FruitDAOImpl对象,new FruitDAOImpl();
        //那么子类的构造方法内部首先调用父类(BaseDAO)的空参构造器,
        //因此此处的getCalss()会被执行,但是获取的是子类FruitDAOImpl的Class
        //所以getGenericSuperclass()获取的是BaeDAO的class
        Type genericType = getClass().getGenericSuperclass();//获取泛型父类类型
        //强转成 ParameterizedType 参数化类型
        //getActualTypeArguments 获取实际的类型参数
        Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
        //只传入了一个参数,数组首位就是我们需要获取的<T>的真实类型
        Type actualType = actualTypeArguments[0];
        //actualType.getTypeName();获取类型名
        try {
            entityClass = Class.forName(actualType.getTypeName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //将加载驱动,连接数据库的操作包装成方法,减少代码复用率
    protected Connection conn(){
        try {
            //加载驱动
            Class.forName(DRIVER);
            //数据库管理器,连接数据库
            connection = DriverManager.getConnection(URL, USER, PSW);
            return connection;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //将关闭资源的操作包装成方法
    protected  void close(ResultSet rs,PreparedStatement pstm,Connection connection){
        try {
            if(rs != null)
                rs.close();
            if(pstm != null)
                pstm.close();
            if(connection != null)
                connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //执行更新,返回影响行数的方法(如果是插入操作,返回自增列主键值)
    protected int executeUpdate(String sql,Object... params){//... params不确定数量的参数
        boolean insertFlag = false;
        insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
        try {
            connection = conn();
            //(sql语句不通用,靠参数传递进来)
            //sql语句
            //String sql = "update t_fruit set fcount = ? where fname like ?";
            //预处理对象
            if(insertFlag){
                pstm = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            }else{
                pstm = connection.prepareStatement(sql);
            }

            setParams(pstm,params);
            int count = pstm.executeUpdate();

            rs = pstm.getGeneratedKeys();

            if(rs.next()){
                return ((Long)rs.getLong(1)).intValue();
            }

            //参数填充也不通用,也靠参数传递进来
            if(params != null && params.length > 0){
                for(int i = 0;i < params.length;++i){
                    pstm.setObject(i+1,params[i]);
                }
            }

            return count;//执行更新,返回影响行数

        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            close( rs, pstm, connection);
        }
        return 0;//影响行数为0
    }


    //通过反射技术,给obj对象的property属性赋propertyValue值
    protected void setValue(Object obj, String property,Object propertyValue){
        Class clazz = obj.getClass();
        try {
            //获取property这个字符串对应的属性名,比如fid去找obj对象中对应的fid属性值
            Field field = clazz.getDeclaredField(property);
            if(field != null){
                field.setAccessible(true);//强制访问(即使private属性也能访问),防止属性为private
                field.set(obj,propertyValue);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    //执行复杂查询,返回... 例如统计结果
    protected Object[] executeComplexQuery(String sql,Object... params){
        try {
            //加载驱动,连接数据库的方法
            connection = conn();
            //预处理对象
            pstm = connection.prepareStatement(sql);
            //执行查询,返回结果集
            rs = pstm.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据:描述结果集信息的数据(有哪些列,什么类型。。。)
            ResultSetMetaData rsmd = rs.getMetaData();

            //获取元数据列数
            int columnCount = rsmd.getColumnCount();
            Object[] columnValueArr = new Object[columnCount];

            if(rs.next()){
                for(int i = 0;i < columnCount;++i){
                    Object columValue = rs.getObject(i + 1);
                    columnValueArr[i] = columValue;

                }
                return columnValueArr;

            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            close( rs, pstm, connection);
        }
        return null;
    }


    //执行查询,返回单个实体对象
    protected T load(String sql,Object... params){
        try {
            //加载驱动,连接数据库的方法
            connection = conn();
            //预处理对象
            pstm = connection.prepareStatement(sql);

            setParams(pstm,params);

            //执行查询,返回结果集
            rs = pstm.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据:描述结果集信息的数据(有哪些列,什么类型。。。)
            ResultSetMetaData rsmd = rs.getMetaData();

            //获取元数据列数
            int columnCount = rsmd.getColumnCount();

            if(rs.next()){
                T entity = (T) entityClass.newInstance();

                for(int i = 0;i < columnCount;++i){
                    String columnName = rsmd.getColumnName(i + 1);
                    Object columValue = rs.getObject(i + 1);
                    setValue(entity,columnName,columValue);
                }
                return entity;

            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally{
            close( rs, pstm, connection);
        }
        return null;
    }


    //给预处理参数设置参数
    protected void setParams(PreparedStatement psmt,Object... params) throws SQLException {
        if(params != null && params.length > 0 ){
            for(int i = 0;i < params.length;++i){
                psmt.setObject(i+1,params[i]);
            }
        }
    }

    // 执行查询,返回结果集并输出
    protected List<T> executeQuery(String sql,Object... params){
        List<T> list = new ArrayList<>();
        try {
            //加载驱动,连接数据库的方法
            connection = conn();
            //预处理对象
            pstm = connection.prepareStatement(sql);

            setParams(pstm,params);

            //执行查询,返回结果集
            rs = pstm.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据:描述结果集信息的数据(有哪些列,什么类型。。。)
            ResultSetMetaData rsmd = rs.getMetaData();

            //获取元数据列数
            int columnCount = rsmd.getColumnCount();

            while(rs.next()){
                T entity = (T) entityClass.newInstance();

                for(int i = 0;i < columnCount;++i){
                    String columnName = rsmd.getColumnName(i + 1);
                    Object columValue = rs.getObject(i + 1);
                    setValue(entity,columnName,columValue);
                }
                list.add(entity);

            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally{
            close( rs, pstm, connection);
        }
        return list;
    }
}

这时候,我们还需要有一个方法来调用BaseDAO类中的通用方法,从而完成查询数据的需求,在这里我们依旧创建一个FruitDAO接口,并创建其实现类FruitDAOImpl类来重写方法,完成功能。

FruitDAO接口
我们需要在浏览器页面中显示数据库的数据,就需要一个获取数据库所有信息的方法。

import com.haojin.fruit.pojo.Fruit;

import java.util.List;

/**
 * @author .29.
 * @create 2022-10-04 16:39
 */
public interface FruitDAO {
    //获取所有的库存信息
    List<Fruit> getFruitList();
}

FruitDAOImpl类
实现类中调用了BaseDAO类中查询数据的通用方法,将SQL语句传入,将获取到的数据存入集合中返回。

import com.haojin.fruit.pojo.Fruit;
import com.haojin.myssm.basedao.BaseDAO;

import java.util.List;

/**
 * @author .29.
 * @create 2022-10-04 16:39
 */
public class FruitDAOImpl extends BaseDAO<Fruit> implements FruitDAO{

    @Override
    public List<Fruit> getFruitList() {
        return super.executeQuery("SELECT * FROM t_fruit");
    }
}


2.使用Servlet组件渲染页面

当我们打开对应的浏览器页面,就会向客户端中的Servlet组件发起一次请求,我们这时候将获取到的数据库数据保存到session保存作用域中,然后在HTML文件中进行渲染,之后将页面响应给客户端的浏览器中,如此一来就在浏览器中显示出数据库数据。

Servlet组件

import com.haojin.fruit.pojo.Fruit;
import com.haojin.fruit.pojo.dao.FruitDAO;
import com.haojin.fruit.pojo.dao.FruitDAOImpl;
import com.haojin.myssm.basedao.myspringmvc.ViewBaseServlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;


/**
 * @author .29.
 * @create 2022-10-04 16:42
 */

//Servlet从3.0版本开始,支持注解方式的注册
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList();

        //保存到session作用域
        HttpSession session = request.getSession();
        session.setAttribute("fruitList",fruitList);

        //此处的视图名称是index
        //那么Thymeleaf会将这个 逻辑视图名称 对应到 物理视图名称上去
        //逻辑视图名称 : index
        //物理视图名称 : view-prefix   +    逻辑视图名称    +    view-suffix
        //所以真实的视图名称是  /        +       index      +      .html
          super.processTemplate("index",request,response);


    }
}

HTML页面

这是我们水果库存系统的浏览器页面代码,在页面中我们会设置一个标题以及一个表格,表格中展示的就是我们数据库中保存的水果库存数据。

因为我们获取到的数据是一个集合,所以在HTML文件中需要用到 Thymeleaf 技术的标签属性:

  • th:if
  • th:unless
  • th:each
  • th:text

循环遍历上文保存在session保存作用域中的数据,如果数据为空,显示库存危机为空:

<tr th:if="${#lists.isEmpty(session.fruitList)}">
		<td colspan = 4>对不起,库存为空!</td>
</tr>

如果保存的数据不为空,获取数据中每一行数据的信息(水果,价格,库存),第四列的删除标志后续功能完善后可以通过点击实现删除操作。

	<tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit:${session.fruitList}">
		<td th:text="${fruit.fname}"></td>
		<td th:text="${fruit.price}"></td>
		<td th:text="${fruit.fcount}"></td>
		<td><img src="del.jpg" width="24px"/></td>
    </tr>

完整html代码

<html xmlns:th="http://www.thymeleaf.org">
 <head>
  <meta charset="UTF-8">
  <style type = "text/css">

  </style>
<link rel = "stylesheet" href = "index.css">

 </head>
 <body>
  <div id = "div_container">
	<div id = "list">
		<p class="center f30">欢迎使用水果库存后台系统</p>
	<table id = "tbl">
	<tr>
		<th class = "w20">名称</th>
		<th class = "w20">单价</th>
		<th class = "w20">库存</th>
		<th>操作</th>
    </tr><br/>

	<tr th:if="${#lists.isEmpty(session.fruitList)}">
		<td colspan = 4>对不起,库存为空!</td>
	</tr>
	<tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit:${session.fruitList}">
		<td th:text="${fruit.fname}"></td>
		<td th:text="${fruit.price}"></td>
		<td th:text="${fruit.fcount}"></td>
		<td><img src="del.jpg" width="24px"/></td>
    </tr>



	</table>
	</div>
  </div>
 </body>
</html>

css效果代码

#div_container{
               width:80%;
			   height:100%;
               border:1px solid white;
			   margin-left:10%;
			   float:left;
			   }
#list{
      width:100%;
      border:0px solid white;
			   }
#tbl , #tbl tr,#tbl th,#tbl td{
	border:1px solid gray;
	text-align:center;
}
#tbl{
	margin-top:120px;
	margin-left:20%;
	width:60%;

}
.w20{
	width:20%;
}
.center{
	text-align: center;
}
.f30{
	font-size: 30px;
}
body{
	padding:0;
	margin:0;
	background-color:aquamarine;
}
div{
	position:relative;
	float:left;
}

.input{
       border:1px solid lightgray;
	   width:90%;
}



三、效果

在这里插入图片描述


总结

这篇文章中,我们将获取到的数据库数据渲染到了浏览器页面上,当然这只不过是开始,我们的水果库存系统还有许多功能没有渲染到页面中,比如新增库存的功能、修改库存的内容、删除指定水果信息的功能、页面的分页功能等。

我将在后续的文章中为客户端页面增添上述提到的内容,逐步完善系统,在完善系统项目的同时,掌握好相关的知识。


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405631.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每天一个CSS小特效,文字闪烁——【钢铁侠:爱你三千遍】

文章目录前言效果图HTML篇CSS篇1. 盒子模型设置2. 动画设置完整代码前言 我是前端小刘不怕牛牛&#xff0c;love you 3000&#xff0c;愿你能遇到值得的人。 今天分享一个唯美的文字闪烁CSS特效 希望大家能喜欢 效果图 HTML篇 代码&#xff1a; <div class"main"…

uniapp中获取dom元素的方法,更改dom元素颜色(遇坑记录)

前言 最近写uniapp&#xff0c;遇到一个需要获取到页面中dom元素&#xff0c;我第一反应是使用this.$ refs进行获取&#xff0c;于是我开心的使用this.$refs写了很多代码&#xff0c;使用h5调试的过程中没有发现任何问题&#xff0c;但后来真机调试的时候发现在app端无效&…

npm安装报错(npm ERR! code EPERM npm ERR! syscall mkdir npm ERR! path C:\Program Files\nodejs\node_ca...)

使用npm安装时候报错了 根据网上经验解决方法&#xff1a; 1.删除.npmrc文件 该文件在&#xff1a;C:\Users{账户}\下的.npmrc文件&#xff0c; 一般这种类型的都是默认被隐藏&#xff0c;一定要选择将隐藏取消掉 删掉即可。 注意&#xff1a;当前方式确实是最有效的操作&…

猿创征文|如何在HbuilderX中运行Vue

第一步&#xff1a;安装Node.js 这里不加赘述&#xff0c;是傻瓜式安装 第二步&#xff1a;找到安装的Node在哪里 如果找不到可以打开cmd 输入 where node 第三步&#xff1a;打开HbuilderX 点击工具 选择设置 如图&#xff1a; 选择运行配置 ②③的位置是需要填写的位置 使用我…

vue项目首屏加载过慢解决方案

前言 因为我的一个vue项目首页打开加载了好久&#xff0c;所以决定优化一下。发现是打包体积太大了&#xff0c;页面才加载慢主要是第三方库。 优化着优化着就想要更好一点&#xff0c;于是逛博客搜索&#xff0c;参照了几个博主的解决方法整理出一下几点。​ 一、防止编译文…

如何在vscode里面快速运行html代码(包含如何在vscode里面编写html代码)

前言必读 读者手册&#xff08;必读&#xff09;_云边的快乐猫的博客-CSDN博客 前言&#xff1a; 1.如何在vscode编写html代码在我的另一篇文章当中有详细教程&#xff0c;这是超链接。 2.很多小伙伴编写了html代码后&#xff0c;在vscode里面右键找不到如何去运行代码&…

NProgress的用法

最近&#xff0c;应该很多小伙伴都找到前端开发的工作了吧。怎么样&#xff1f;工作中的代码是不是比机构学的代码复杂很多倍&#xff1f; 比如说 router里面的路由钩子函数是不是比学习的时候复杂很多倍&#xff1f;还有vuex模块是不是会见到许许多多的文件夹&#xff0c;每个…

vue长列表优化之虚拟列表实现

vue长列表优化之虚拟列表实现 应用场景:后台一次性发送上千条或更多数据给前台 场景模拟:用户发起一个请求,后台发送了10w条数据 使用虚拟列表之前:前台需要生成10w个dom节点用来渲染页面 使用虚拟列表之后:前台只需要生成少量dom节点(dom节点数量取决于前端视图需要展示的…

html中常见标签及其用法归纳大全

html零基础必看——htmlHTML常见标签大全 第二章&#xff1a;html常见标签前言一、常见标签&#xff08;一&#xff09;1、body标签2、div盒子标签3、p文本段落标签4、h1~h6 标题标签5、b标签和strong标签&#xff08;文字加粗标签&#xff09;6、span文字包裹标签7、br换行标签…

大二学生web期末大作业 在线电影网站 HTML+CSS+JS

&#x1f329;️ 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f482; 作者主页: 【进入主页—&#x1f680;获取更多源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;HTML5网页期末作业 (1000套…

ES6展开运算符“...”

● ES6新增了一个运算符“...”&#xff0c;叫做展开运算符 ● 作用是把数组或者对象内容展开 &#xff08;1&#xff09;展开数组&#xff1a; ○ ES5方法&#xff1a;concat&#xff08;&#xff09; <script>let a [1,2,3]let b [4,5,6]//ES5的方法&#xff1a;c…

【百度地图】百度地图的使用方法 和 在vue中如何使用百度地图(超详细)

【百度地图】百度地图的使用方法 和 在vue中如何使用百度地图&#xff08;超详细&#xff09; 1- 介绍 百度地图功能强大&#xff0c;本篇文章只是对百度地图JavaScript API 进行一个介绍~ 官方网址 百度地图开放平台LBS&#xff1a;LocationBusinessServer 基于定义位置的商…

JS 连接MQTT的方法(mqtt.js的使用方法)

本文章是介绍 mqtt.js 的使用方法 一、说明 本文章使用的版本是 4.1.x &#xff0c;没用最新版的原因是 4.2.x 以上版本会报错&#xff0c;具体报错可以看我的另一篇文章&#xff0c;点击查看。使用的 4.1.x 版本地址&#xff1a;https://cdn.bootcdn.net/ajax/libs/mqtt/4.1…

若依 vue前端 动态设置路由path不同参数 在页面容器里打开新页面(新路由),面包屑和标签页标题根据参数动态改变,面包屑多级标题,侧边栏对应菜单亮起

前言 因为是在vue源码的基础上进行修改&#xff0c;所以&#xff0c;就没有复制代码在文章上&#xff0c;采取的是截图对比源码和我修改的代码片段。要麻烦你们自己手敲了。 先来看看效果&#xff1a; 场景&#xff1a;在费用配置列表中&#xff0c;点击每一项的配置&#x…

vue如何设置元素的显示隐藏

方法&#xff1a;可以使用v-if&#xff0c;也可以使用v-show指令。 v-if 指令&#xff0c;通过动态的向DOM树内添加或者删除DOM元素的方式来显示或隐藏元素&#xff1b; v-show 指令&#xff0c;通过设置DOM元素的display样式属性来控制显隐。 区别&#xff1a; v-if 会直接删除…

手把手教你在 Vue3 中自定义指令

TienChin 项目前端是 Vue3&#xff0c;前端有这样的一个需求&#xff1a;有一些前端页面上的按钮要根据用户的权限来决定是否展示出来&#xff0c;如果用户具备相应的权限&#xff0c;那么就展示对应的按钮&#xff1b;如果用户不具备对应的权限&#xff0c;那么按钮就隐藏起来…

微信小程序:用户微信登录流程(附:流程图+源码)

目录 前言 一、微信小程序是什么&#xff1f; 二、业务流程 1、使用微信小程序登录的wx.login()方法 2、后端使用登录凭证换取session_key和openid 3、前端处理session_key、openid和token 尾言 前言 随着微信小程序大规模的铺开和宣传&#xff0c;在生活中随处可见微信小程序…

vue2常见面试题

文章目录1、vue 修改数据页面不重新渲染数组/对象的响应式 &#xff0c;vue 里面是怎么处理的&#xff1f;2、生命周期Vue 生命周期都有哪些&#xff1f;父子组件生命周期执行顺序3、watch 和 computed 的区别4、组件通信&#xff08;组件间传值&#xff09;5、$nextTick6、修饰…

【微信小程序】自定义组件(二)

&#x1f381;写在前面&#xff1a; 观众老爷们好呀&#xff0c;这里是前端小刘不怕牛牛频道&#xff0c;小程序系列文章又更新了呀。 上文我们讲解了微信小程序自定义组件的入门知识&#xff0c;那么今天牛牛就来讲讲自定义组件的进阶知识吧&#xff0c;赶紧拿起小本本做笔记…

vue中三种for循环(含案例分析)

这里写目录标题三种for循环1.普通的for循环2.for in 循环3.for of 循环总结三种for循环 vue中的for循环有三种 :1.普通的for循环 ,2.for in 循环 ,3.for of 循环 它们三个各自有各自的特点和作用&#xff0c;下面我会用一个小案例来帮助大家理解它们三个的区别 &#xff08;三…