Ajax、Axios、Vue、Element与其案例

目录

一.Ajax

二.Axios

三.Vue

四.Element

五.增删改查案例

一.依赖:数据库,mybatis,servlet,json-对象转换器

二.资源:element+vue+axios

三.pojo

四.mapper.xml与mapper接口

五.service

六.servlet

七.html页面


建立web工程

需要的依赖:

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.62</version>
    </dependency>

一.Ajax

复制代码
AJAX(Asynchronous JavaScript And XML):异步的js和xml
异步交互:与服务器交换数据并且更新部分网页的技术(局部刷新),操作无需等待服务器响应,直到数据响应回来才改变html页面
本案例使用ajax请求数据与处理响应数据,发送路径需要使用全路径

01ajax.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
</body>
<script>
    xhttp = new XMLHttpRequest();
    xhttp.open("GET", " http://localhost/web_demo5_ajax_war/ajaxServlet");
    xhttp.send();
    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            alert(this.responseText);
        }
    };
</script>
</html>

@WebServlet("/ajaxServlet")
public class AJAXServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().write("Hello,AJAX!");
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

二.Axios

复制代码
Axios对原生的ajax封装,简化书写
使用准备:导入js文件,放到js文件里面,在本文件中引入js
本案例为使用axios用不同请求方式请求数据并处理响应数据

02axios.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script src="js/axios-0.18.0.js"></script>
<script>
    axios.get("http://localhost/web_demo5_ajax_war/axiosServlet?username=zhangsan").then(resp=>{alert(resp.data)})
    axios.post("http://localhost/web_demo5_ajax_war/axiosServlet","username=zhangsan").then(resp=>{alert(resp.data)})
</script>
</html>

@WebServlet("/axiosServlet")
public class AxiosServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().write(request.getMethod());
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

浏览器弹窗为两种不同的请求方式

三.Vue

复制代码
Vue是一套前端的框架,在js中简化Dom操作
使用需要:导入vue.js
复制代码
1.改变框里面的值,对应的路径也改变
    1.绑定表单中的输入使用:v-model="url"
    2.绑定超链接跳转路径属性使用:v-bind:href="url"或:href="url"
    3.展示绑定模型的内容使用:{{}}}
2.点击按钮调用不同方法
    1.绑定事件元素使用:v-on:click="show()或者@click="show()"
    2.引入方法:在js的Vue模块中使用methods
3.通过输入展示不同标签
    1.if else:使用v-if="条件"属性
    2.展示内容与否:使用v-show标签
4.遍历模型:使用v-for=""属性
    在此案例中addr为局部变量名称,根据情况选择是否使用索引
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <input v-model="url"><br>
    <a v-bind:href="url">{{url}}</a><br>
    <a :href="url">{{url}}</a><br><br><br>

    <input type="button" value="按钮1" v-on:click="show()"><br>
    <input type="button" value="按钮2" @click="show()"><br><br><br>

    <div v-if="count==1">div1</div>
    <div v-else-if="count==2">div2</div>
    <div v-else>div3</div>
    <div v-show="count==4">div4</div>
    <input v-model="count"><br><br><br>

    <div v-for="addr in addrs">
        {{addr}}<br>
    </div>
    <div v-for="(addr,i) in addrs">
        {{i+1}}--{{addr}}<br>
    </div>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({//创建vue核心对象
        el:"#app",//作用范围
        methods:{//方法
            show(){
                alert("按钮被点击")
            }
        },
        data(){//模型数据
            return {
                url:"https://www.baidu.com",
                count:1,
                addrs:["北京","上海","西安"]
            }
        },
        mounted(){//页面加载完成后的方法
            alert("加载完成")
        }
    })
</script>
</body>
</html>

四.Element

复制代码
1.复制粘贴element-ui文件
2.引文件使用:然后去官网复制粘贴即可
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="app">
    <el-row>
        <el-button>默认按钮</el-button>
        <el-button type="primary">主要按钮</el-button>
        <el-button type="success">成功按钮</el-button>
        <el-button type="info">信息按钮</el-button>
        <el-button type="warning">警告按钮</el-button>
        <el-button type="danger">危险按钮</el-button>
    </el-row>
</div>
</body>
<link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">
<script src="js/vue.js"></script>
<script src="element-ui/lib/index.js"></script>
<script>
  new Vue({
    el:"#app"
  })
</script>
</html>

五.增删改查案例

新建Web项目

一.依赖:数据库,mybatis,servlet,json-对象转换器
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.5</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.62</version>
    </dependency>
二.资源:element+vue+axios
三.pojo

brand类中使用到了getStatusStr方法:由status返回字符串,交给别的类调用

public class Brand {
    private Integer id;
    private String brandName;
    private String companyName;
    private Integer ordered;
    private String description;
    private Integer status;
    public Brand() {
    }
    public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
        this.id = id;
        this.brandName = brandName;
        this.companyName = companyName;
        this.ordered = ordered;
        this.description = description;
        this.status = status;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getBrandName() {
        return brandName;
    }
    public void setBrandName(String brandName) {
        this.brandName = brandName;
    }
    public String getCompanyName() {
        return companyName;
    }
    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }
    public Integer getOrdered() {
        return ordered;
    }
    public void setOrdered(Integer ordered) {
        this.ordered = ordered;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Integer getStatus() {
        return status;
    }
    public String getStatusStr(){
        if(this.status==1){ return "启用"; }
        return "禁用";
    }
    public void setStatus(Integer status) {
        this.status = status;
    }
    @Override
    public String toString() {
        return "Brand{" +
                "id=" + id +
                ", brandName='" + brandName + '\'' +
                ", companyName='" + companyName + '\'' +
                ", ordered=" + ordered +
                ", description='" + description + '\'' +
                ", status=" + status +
                '}';
    }
}

pagebean类用于存放一页的数据与总数量

public class PageBean<T> {
    private int totalCount;
    private List<T> rows;
    public PageBean() {
    }
    public PageBean(int totalCount, List<T> rows) {
        this.totalCount = totalCount;
        this.rows = rows;
    }
    public int getTotalCount() {
        return totalCount;
    }
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }
    public List<T> getRows() {
        return rows;
    }
    public void setRows(List<T> rows) {
        this.rows = rows;
    }
}
四.mapper.xml与mapper接口

使用到了批量删除、模糊查询、分页查询

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.BrandMapper">
    <resultMap id="brandResultMap" type="Brand">
        <id column="id" property="id"/>
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>
    <delete id="deleteByIds">
        delete from tb_brand where id in
        <foreach collection="array" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>;
    </delete>
    <select id="selectByPageAndCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="brand.status!=null">
                and  status=#{brand.status}
            </if>
            <if test="brand.companyName!=null and brand.companyName!=''">
                and company_name like #{brand.companyName}
            </if>
            <if test="brand.brandName!=null and brand.brandName!=''">
                and brand_name like #{brand.brandName}
            </if>
        </where>
        limit #{begin},#{size}
    </select>
    <select id="selectCountByCondition" resultType="java.lang.Integer">
        select count(*) from tb_brand
        <where>
            <if test="status!=null">
                and  status=#{status}
            </if>
            <if test="companyName!=null and companyName!=''">
                and company_name like #{companyName}
            </if>
            <if test="brandName!=null and brandName!=''">
                and brand_name like #{brandName}
            </if>
        </where>
    </select>
</mapper>

public interface BrandMapper {
    //添加数据
    @Insert("insert into tb_brand values(null,#{brandName},#{companyName},#{ordered},#{description},#{status})")
    void add(Brand brand);
    //删除数据
    @Delete("delete from tb_brand where id=#{id}")
    void deleteById(int id);
    //更新数据
    @Update("update tb_brand set brand_name=#{brandName}," +
            "company_name=#{companyName}," +
            "ordered=#{ordered}," +
            "description=#{description}," +
            "status=#{status} " +
            "where id=#{id}")
    void update(Brand brand);
    //删除选中数据
    void deleteByIds(int[] ids);
    //条件分页查询
    int selectCountByCondition(Brand brand);
    List<Brand> selectByPageAndCondition(@Param("begin") int begin, @Param("size") int size, @Param("brand") Brand brand);

}
五.service
public class BrandService {
    SqlSessionFactory factory = SqlSessionFactoryUtil.getssf();
    public void add(Brand brand) {
        SqlSession sqlsession=factory.openSession(true);
        sqlsession.getMapper(BrandMapper.class).add(brand);
        sqlsession.close();
    }
    public void deleteById(int id) {
        SqlSession sqlsession=factory.openSession(true);
        sqlsession.getMapper(BrandMapper.class).deleteById(id);
        sqlsession.close();
    }
    public void update(Brand brand) {
        SqlSession sqlsession=factory.openSession(true);
        sqlsession.getMapper(BrandMapper.class).update(brand);
        sqlsession.close();
    }
    public void deleteByIds(int[] ids) {
        SqlSession sqlsession=factory.openSession(true);
        sqlsession.getMapper(BrandMapper.class).deleteByIds(ids);
        sqlsession.close();
    }
    public PageBean<Brand> selectByPageAndCondition(int currentPage, int pageSize, Brand brand) {
        SqlSession sqlsession=factory.openSession(true);
        BrandMapper mapper=sqlsession.getMapper(BrandMapper.class);
        String brandName=brand.getBrandName();
        if(brandName!=null && !brandName.isEmpty()) brand.setBrandName("%"+brandName+"%");
        String companyName=brand.getCompanyName();
        if(companyName!=null && !companyName.isEmpty()) brand.setCompanyName("%"+companyName+"%");

        PageBean<Brand> pageBean=new PageBean<>(mapper.selectCountByCondition(brand),
                        mapper.selectByPageAndCondition((currentPage-1)*pageSize,pageSize,brand));
        sqlsession.close();
        return pageBean;
    }
}
六.servlet

服务类中使用反射判别不同的请求路径去访问不同方法

public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String uri=req.getRequestURI();
        String methodName=uri.substring(uri.lastIndexOf('/')+1);
        Class<? extends BaseServlet> cls=this.getClass();
        try{
            Method method=cls.getMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
            method.invoke(this,req,resp);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

分页+模糊查询同时使用到了post+get方法

@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet{
    private final BrandService service =new BrandService();
    public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("add...");
        service.add(JSON.parseObject(request.getReader().readLine(),Brand.class));
        response.getWriter().write("success");
    }
    public void deleteById(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        System.out.println("deleteById...");
        service.deleteById(Integer.parseInt(request.getParameter("id")));
        response.getWriter().write("success");
    }
    public void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        System.out.print("update...");
        service.update(JSON.parseObject(request.getReader().readLine(),Brand.class));
        response.getWriter().write("success");
    }
    public void deleteByIds(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        System.out.print("deleteMany...");
        service.deleteByIds(JSON.parseObject(request.getReader().readLine(),int[].class));
        response.getWriter().write("success");
    }
    //post+get方式来实现分页查询+条件查询,条件查询可有可无
    public void selectByPageAndCondition(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("brand selectByPageAndCondition...");
        response.setContentType("text/json;charset=UTF-8");
        response.getWriter().write(
                JSON.toJSONString(
                        service.selectByPageAndCondition(
                                Integer.parseInt(request.getParameter("currentPage")),
                                Integer.parseInt(request.getParameter("pageSize")),
                                JSON.parseObject(request.getReader().readLine(),Brand.class)
                        )));
    }
}
七.html页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <!--查询表单-->
    <el-form :inline="true" :model="brandSelect" class="demo-form-inline">
        <el-form-item label="当前状态">
            <el-select v-model="brandSelect.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="brandSelect.companyName" placeholder="企业名称"></el-input>
        </el-form-item>
        <el-form-item label="品牌名称">
            <el-input v-model="brandSelect.brandName" placeholder="企业名称"></el-input>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="selectAll">查询</el-button>
        </el-form-item>
    </el-form>
    <!--新增与批量删除按钮-->
    <el-row>
        <el-button type="danger" plain @click="deleteByIds">批量删除</el-button>
        <el-button type="primary" plain @click="handleAdd">新增</el-button>
    </el-row>
    <!--添加数据与修改数据的对话框表单-->
    <el-dialog
            title="编辑品牌"
            :visible.sync="dialogVisible"
            width="30%">
        <el-form ref="form" :model="brand" label-width="80px">
            <el-form-item label="品牌名称">
                <el-input v-model="brand.brandName"></el-input>
            </el-form-item>
            <el-form-item label="企业名称">
                <el-input v-model="brand.companyName"></el-input>
            </el-form-item>
            <el-form-item label="排序">
                <el-input v-model="brand.ordered"></el-input>
            </el-form-item>
            <el-form-item label="备注">
                <el-input type="textarea" v-model="brand.description"></el-input>
            </el-form-item>
            <el-form-item label="状态">
                <el-switch v-model="brand.status"
                           active-color="#13ce66"
                           inactive-color="#ff4949"
                           active-value="1"
                           inactive-value="0">
                </el-switch>
            </el-form-item>
            <!--点击事件设立一下-->
            <el-form-item>
                <template v-if="method=='修改'">
                    <el-button type="primary" @click="updateBrand">提交修改</el-button>
                </template>
                <template v-else>
                    <el-button type="primary" @click="addBrand">提交添加</el-button>
                </template>
                <el-button @click=cancelUpdate>取消</el-button>
            </el-form-item>
        </el-form>
    </el-dialog>
    <!--表格-->
    <el-table
            :data="tableData"
            style="width: 100%"
            stripe
            @selection-change="handleSelectionChange">
        <el-table-column
                type="selection">
        </el-table-column>
        <el-table-column
                label="排序"
                type="index">
        </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>
        <!--取值为statusStr,找到Brand里面的对应的get方法-->
        <el-table-column
                prop="statusStr"
                align="center"
                label="当前状态">
        </el-table-column>
        <el-table-column label="操作" align="center">
            <template slot-scope="scope">
                <el-button
                        type="primary"
                        @click="handleEdit(scope.$index, scope.row)">编辑
                </el-button>
                <el-button
                        type="danger"
                        @click="handleDelete(scope.$index, scope.row)">删除
                </el-button>
            </template>
        </el-table-column>
    </el-table>
    <!--分页-->
    <el-pagination
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page="currentPage"
            :page-sizes="[5, 10, 15, 20]"
            :page-size="100"
            layout="total, sizes, prev, pager, next, jumper"
            :total="totalCount">
    </el-pagination>
</div>
<script src="js/axios-0.18.0.js"></script>
<script src="js/vue.js"></script>
<script src="element-ui/lib/index.js"></script>
<link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">
<script>
    new Vue({
        el: "#app",
        mounted() {
            this.selectAll();
        },
        data() {
            return {
                //表内数据与查询的数据
                tableData: [],
                brandSelect: {
                    status: '',
                    brandName: '',
                    companyName: '',
                    description: '',
                    id: '',
                    ordered: '',
                },
                //add与update表单显示开关,方法选择,使用的模型
                dialogVisible: false,
                method: '',
                brand: {},
                //复选框数据,选中的要删除的数据
                multipleSelection: [],
                selectedIds: [],
                //分页数据
                pageSize: 5,
                totalCount: 100,
                currentPage: 1,
            }
        },
        methods: {
            //添加功能与修改功能
            handleAdd() {
                this.method = '添加';
                this.brand = {
                    status: '',
                    brandName: '',
                    companyName: '',
                    description: '',
                    id: '',
                    ordered: '',
                };
                this.dialogVisible = true
            },
            handleEdit(index, row) {
                this.method = '修改'
                this.brand = this.tableData[index];
                this.brand.status = String(this.brand.status)
                this.dialogVisible = true;
            },
            addBrand() {
                axios.post("http://localhost/web_demo6_war/brand/add", this.brand).then(resp => {
                    if (resp.data == "success") {
                        this.dialogVisible = false;
                        this.$message({
                            message: '添加成功',
                            type: 'success'
                        });
                        this.selectAll();
                    }
                })
            },
            updateBrand() {
                axios.post("http://localhost/web_demo6_war/brand/update", this.brand).then(resp => {
                    if (resp.data == "success") {
                        this.dialogVisible = false;
                        this.$message({
                            message: '修改成功',
                            type: 'success'
                        });
                        this.selectAll();
                    }
                })
            },
            cancelUpdate() {
                this.dialogVisible = false
                this.$message({
                    message: '已取消修改',
                });
                this.selectAll()
            },

            //删除功能
            handleDelete(index, row) {
                this.$confirm('此操作将永久删除改公司信息, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    axios.get("http://localhost/web_demo6_war/brand/deleteById?id=" + this.tableData[index].id).then(resp => {
                        if (resp.data == "success") {
                            this.$message({
                                message: '删除成功',
                                type: 'success'
                            });
                            this.selectAll();
                        }
                    })
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },

            //批量删除功能
            handleSelectionChange(val) {
                this.multipleSelection = val;
                console.log(this.multipleSelection);
            },
            deleteByIds() {
                for (let i = 0; i < this.multipleSelection.length; i++) {
                    let selectedElement = this.multipleSelection[i];
                    this.selectedIds[i] = selectedElement.id;
                }
                this.$confirm('此操作将永久删除改公司信息, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    if (this.selectedIds.length != 0) {
                        axios.post("http://localhost/web_demo6_war/brand/deleteByIds", this.selectedIds).then(resp => {
                            if (resp.data == "success") {
                                this.$message({
                                    message: '删除成功',
                                    type: 'success'
                                });
                                this.selectAll();
                            }
                        })
                        this.selectedIds = [];
                    } else {
                        this.$message({
                            message: '需要选中几个数据',
                            type: 'warning'
                        });
                    }
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },


            //分页工具条方法
            handleSizeChange(val) {
                console.log(`每页 ${val} 条`);
                this.pageSize = val;
                this.selectAll();
            },
            handleCurrentChange(val) {
                console.log(`当前页: ${val}`);
                this.currentPage = val;
                this.selectAll();
            },
            //查询分页:
            selectAll() {
                axios.post("http://localhost/web_demo6_war/brand/selectByPageAndCondition?currentPage=" + this.currentPage + "&pageSize=" + this.pageSize,
                    this.brandSelect).then(resp => {
                    this.tableData = resp.data.rows;
                    this.totalCount = resp.data.totalCount;
                    console.log(this.tableData);
                })
            },
        }
    })
</script>
</body>
</html>

在本文的最后,说一些最近的感想:

学习这类技术似乎不能太认真,或许会浪费大把的时间

"作数"或许就行了!

相关推荐
LvManBa1 分钟前
HTML5中新增元素介绍
前端·html·html5
程序员阿龙24 分钟前
计算机毕业设计之:基于uni-app的校园活动信息共享系统设计与实现(三端开发,安卓前端+网站前端+网站后端)
前端·uni-app·移动端开发·校园应用开发·实时信息共享·信息系统设计与实现·校园活动管理
shangtaobocdns1 小时前
django+vue
vue.js·python·django
天蓝蓝235281 小时前
Vue.js与Flask/Django后端配合
vue.js·django·flask
让开,我要吃人了1 小时前
HarmonyOS鸿蒙开发实战(5.0)表情图片聊天案例实践
前端·华为·移动开发·harmonyos·鸿蒙·harmonyos next·鸿蒙开发
GISer_Jing1 小时前
Vue.js与Flask/Django后端配合
vue.js·django
笃励3 小时前
Angular面试题二
前端·javascript·angular.js
速盾cdn4 小时前
速盾:高防 CDN 怎么屏蔽恶意访问?
前端·网络·web安全
javaer炒粉6 小时前
provide,inject父传子
javascript·vue.js·elementui
LvManBa6 小时前
Vue学习记录之五(组件/生命周期)
javascript·vue.js·学习