jQuery实现级联下拉框实战(5)


Posted in Javascript onFebruary 08, 2017

今天来完成jQuery实战的级联下拉框效果。效果功能如下:

jQuery实现级联下拉框实战(5)

页面默认只提供汽车厂商,当选择了具体的某品牌汽车,汽车类型下拉框就会动态的显示出来,选择对应的类型,然后出来该汽车类型对应的轮胎类型下拉框显示出来,选中轮胎类型,页面的正中间会显示出汽车的图片。
思路分析如图:

jQuery实现级联下拉框实战(5)

建立我们的html页面,程序清单如下:

代码清单1.1: chainSelect.jsp

<body>
 <div class="loading">
 <p><img src="../image/data-loading.gif" alt="数据装载中" /></p>
 <p>数据装载中......</p>
 </div> 
 <div class="car">
 <span class="carname"> 
 汽车厂商:
 <select>
 <option value="" selected="selected">请选择汽车厂商</option>
 <option value="BMW">宝马</option>
 <option value="Audi">奥迪</option>
 <option value="VW">大众</option>
 </select>
 <img src="../image/pfeil.gif" alt="有数据">
 </span>
 <span class="cartype">
 汽车类型:
 <select>
 <option selected="selected">默认选项</option>
 <option>Test1</option>
 </select>
 <img alt="有数据" src="../image/pfeil.gif">
 </span>
 <span class="wheeltype">
 车轮类型:
 <select>
 <option selected="selected">默认选项</option>
 <option>Test1</option>
 </select>
 </span>
 </div>
 <div class="carimage">
 <p><img src="../image/img-loading.gif" alt="图片装载中" class="carloading"></p>
 <p><img src="" alt="汽车图片" class="carimg"></p>
 </div>
</body>

body体里面囊括了3个div,第一个div的作用是显示“数据正在装载中…”的图片和文字。第二个div显示级联下拉效果。第三个div显示车辆图片。

css代码如下:

代码清单1.2:chainSelect.css

.loading {
 width: 400px;
 margin: 0 auto;
/* visibility: hidden; */
}
.loading p {
 text-align: center;
}
p {
 margin: 0;
}
.car {
 text-align: center;
}
.carimage {
 text-align: center;
}
.cartype, .wheeltype, .carloading, .carimg, .car img {
 display: none;
}

代码清单1.3:chainSelect.js

$(document).ready(function(){
 //找到三个下拉框
 var carnameSelect = $(".carname").children("select");
 var cartypeSelect = $(".cartype").children("select");
 var wheeltypeSelect = $(".wheeltype").children("select");

 carnameSelect.change(function(){
 console.log("汽车厂商触发onChange事件");
 });
 cartypeSelect.change(function(){
 console.log("汽车类型触发onChange事件");
 });
 wheeltypeSelect.change(function(){
 console.log("车轮触发onChange事件");
 });
});

首先用jQuery的class选择器选择出三个下拉的框,当它们的值改变时触发对应的jQuery函数,对jQuery函数的处理才是重点的内容。
首先说到jQuery中的ajax交互。前一篇我们用到get()的请求方式,今天来用以用post()方法的请求方式。

jQuery.post(url, [data], [callback], [type])

概述:

通过远程 HTTP POST 请求载入信息.这是一个简单的 POST 请求功
能以取代复杂ajax() 。请求成功时可调>用回调函数。如果需要在出错时执行函数,请使用 $.ajax。

参数含义:

url:发送请求地址。
data:待发送 Key/value 参数。
callback:发送成功时回调函数。
type:返回内容格式,xml, html, script, json, text, _default。

案例如下:

代码清单1.4:demo.js

$(document).ready(function(){
 //发起ajax请求
 $.post("../chainSelect", {name: "John", time: "2pm"}, function(data){
 console.log("name : " + data.name);
 console.log("type : " + data.type);
 }, "json");
});

后台Serlvet处理如下(当然你可以使用java框架,也可以使用其他后台语言)。

代码清单1.5:demo.java

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

public class ChainSelect extends HttpServlet {
 private static final long serialVersionUID = 1L;

 protected void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 System.out.println("name = " + request.getParameter("name"));
 System.out.println("time = " + request.getParameter("time"));

 response.setCharacterEncoding("UTF-8");
 response.setContentType("application/json; charset=utf-8");
 String jsonStr = "{\"name\":\"fly\",\"type\":\"虫子\"}";
 PrintWriter out = null;
 try {
 out = response.getWriter();
 out.write(jsonStr);
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 if (out != null) {
 out.close();
 }
 }

 }

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

别忘了纯Serlvet部属要在你的web.xml做配置。我的Serlvet的完整路进地址是:http://localhost:8080/JqueryStudy/chainSelect ,两句System.out.println()输出ajax传递过来的参数name和time。response.setCharacterEncoding(“UTF-8”)的作用是告诉浏览器字符串为utf-8的编码,防止中文乱码问题。response.setContentType(“application/json; charset=utf-8”)将返回的字符串以json格式形式返回。out对象是输出流,如果返回的是数组,格式应该如下:[“test1”, “test2”, “test3”],如果是json类,则格式如下:{“name”:”fly”,”type”:”虫子”}。

上诉案例返回的是json对象,后台控制台输出:

name = John
time = 2pm

前端浏览器的控制台输出:

name : fly
type : 虫子

Servlet返回数组的案例如下:

代码清单1.6:demo.java

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

public class ChainSelect extends HttpServlet {
 private static final long serialVersionUID = 1L;

 protected void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 System.out.println("name = " + request.getParameter("name"));
 System.out.println("time = " + request.getParameter("time"));

 response.setCharacterEncoding("UTF-8");
 response.setContentType("application/json; charset=utf-8");
 String jsonStr = "[\"test1\", \"test2\", \"test3\"]";
 PrintWriter out = null;
 try {
 out = response.getWriter();
 out.write(jsonStr);
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 if (out != null) {
 out.close();
 }
 }

 }

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

前端jQuery代码:

$(document).ready(function(){
 //发起ajax请求
 $.post("../chainSelect", {name: "John", time: "2pm"}, function(data){
 for(var i = 0; i < data.length; i++) {
 console.log((i+1) + " : " + data[i]);
 }
 }, "json");
});

后台之需要给jsonStr赋值为数组格式而已,而前端jQuery代码由于接收到的字符串数组,所以这里需要用遍历数组的形式来遍历。

本案例的Servlet代码清单:

代码清单1.7:ChainSelect.java

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

public class ChainSelect extends HttpServlet {
 private static final long serialVersionUID = 1L;

 protected void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 response.setCharacterEncoding("UTF-8");
 response.setContentType("application/json; charset=utf-8");
 String jsonStr = this.getStr(request.getParameter("keyword"), request.getParameter("type"));
 PrintWriter out = null;
 try {
 out = response.getWriter();
 out.write(jsonStr);
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 if (out != null) {
 out.close();
 }
 }

 }

 private String getStr(String keyword, String type) {
 String jsonStr = "";
 if("top".equals(type)) {
 if("BMW".equals(keyword)) {
 jsonStr = "[\"316ti\", \"6ercupe\"]";
 } else if("Audi".equals(keyword)) {
 jsonStr = "[\"tt\"]";
 } else if("VW".equals(keyword)) {
 jsonStr = "[\"Golf4\"]";
 }
 } else if("sub".equals(type)) {
 if("tt".equals(keyword)) {
 jsonStr = "[\"rha\", \"rhb\", \"rhc\"]";
 } else if("316ti".equals(keyword)) {
 jsonStr = "[\"rha\", \"rhb\"]";
 } else if("6ercupe".equals(keyword)) {
 jsonStr = "[\"rha\", \"rhb\", \"rhc\"]";
 } else if("Golf4".equals(keyword)) {
 jsonStr = "[\"rha\", \"rhb\"]";
 }
 }
 return jsonStr;
 }
 protected void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 doGet(request, response);
 }
}

代码清单1.7与清单1.6的区别是,后者多了getStr()的方法,该方法用于判断前端传递过来的是一级(top)下拉框的值,还是二级(sub)下拉框的值,并根据传递的keyword返回需要的字符串。与本后台交互的是程序清单1.8所示的代码。

程序清单1.8:chainSelect.js

/**
 * 级联下拉框效果
 */

$(document).ready(function(){
 //找到三个下拉框
 var carnameSelect = $(".carname").children("select");
 var cartypeSelect = $(".cartype").children("select");
 var wheeltypeSelect = $(".wheeltype").children("select");

 carnameSelect.change(function(){
 var carname = carnameSelect.val();
 if(carname != "") {
 //汽车厂商不为空发起ajax请求
 $.post("../chainSelect", {keyword: carname, type : "top"}, function(data){
 if(data != null && data.length != 0) {
  //清除上一次change的内容
  cartypeSelect.html("");
  $("<option value=''>请选择汽车类型</option>").appendTo(cartypeSelect);
  for(var i = 0; i < data.length; i++) {
  $("<option value='"+data[i]+"'>"+data[i]+"</option>").appendTo(cartypeSelect);
  }
  $(".cartype").show();
  carnameSelect.next("img").show();
 }
 }, "json");
 } else {
 //3.如果值为空,那么第二个下拉框所在span要隐藏起来,第一个下拉框后面的指示图片也要隐藏
 $(".cartype").hide();
 $(".wheeltype").hide();
 $(".carimage").hide();
 $(this).next("img").hide();
 }
 });

 cartypeSelect.change(function(){
 var cartype = cartypeSelect.val();
 if(cartype != "") {
 //汽车类型不为空发起ajax请求
 $.post("../chainSelect", {keyword: cartype, type : "sub"}, function(data){
 if(data != null && data.length != 0) {
  //清除上一次change的内容
  wheeltypeSelect.html("");
  $("<option value=''>请选择车轮类型</option>").appendTo(wheeltypeSelect);
  for(var i = 0; i < data.length; i++) {
  $("<option value='"+data[i]+"'>"+data[i]+"</option>").appendTo(wheeltypeSelect);
  }
  $(".wheeltype").show();
  cartypeSelect.next("img").show();
 }
 }, "json");
 } else {
 //汽车类型为空
 $(".wheeltype").hide();
 $(".carimage").hide();
 $(this).next("img").hide();
 } 
 });

 wheeltypeSelect.change(function(){
 //选中的车轮类型
 var wheeltype = wheeltypeSelect.val();

 if(wheeltype != "") {
 //选中的车辆厂商
 var carname = carnameSelect.val();
 //选中的车辆类型
 var cartype = cartypeSelect.val();

 //图片的名称
 var carimgName = carname + "_" + cartype + "_" + wheeltype + ".jpg";
 console.log("carimgName : " + carimgName);

 $(".carimage").show();

 $(".carimg").attr("src", "../image/" + carimgName).load(function(){
 //隐藏loading图片
 $(".carloading").hide("slow");
 });
 $(".carimage p img").show("slow");
 } else {
// alert("内容为空");
// $("img").hide();
 $(".carimage").hide();
 }
 });

 //给数据装载中的节点定义ajax事件,实现动画提示效果
 $(".loading").ajaxStart(function(){
 $(this).css("visibility", "visible");
 $(this).animate({
 opacity: 1
 },0);
 }).ajaxStop(function(){
 $(this).animate({
 opacity: 0
 },500);
 });
});

jQuery代码的思路是,用class选择器选择出三个下拉框,赋值给变量carnameSelect,cartypeSelect,wheeltypeSelect,默认carnameSelect下拉框是显示的,其他下拉框是隐藏。然后给他们三者注册change()事件,当用户选择下拉框的值的时候执行事件函数体里面的内容。这里我以第一级下拉框为例来讲解处理的过程。如果用户选择了第一级下拉框”汽车厂商”的”宝马”,则执行如下代码:

carnameSelect.change(function(){
 var carname = carnameSelect.val();
 if(carname != "") {
 //汽车厂商不为空发起ajax请求
 $.post("../chainSelect", {keyword: carname, type : "top"}, function(data){
 if(data != null && data.length != 0) {
  //清除上一次change的内容
  cartypeSelect.html("");
  $("<option value=''>请选择汽车类型</option>").appendTo(cartypeSelect);
  for(var i = 0; i < data.length; i++) {
  $("<option value='"+data[i]+"'>"+data[i]+"</option>").appendTo(cartypeSelect);
  }
  $(".cartype").show();
  carnameSelect.next("img").show();
 }
 }, "json");
 } else {
 //3.如果值为空,那么第二个下拉框所在span要隐藏起来,第一个下拉框后面的指示图片也要隐藏
 $(".cartype").hide();
 $(".wheeltype").hide();
 $(".carimage").hide();
 $(this).next("img").hide();
 }
 });

先将第一级下拉框内容取出来,如果值为空,那么第二个下拉框所在span要隐藏起来,第一个下拉框后面的指示图片也要隐藏。如果有内容, 则用该行代码$.post(“../chainSelect”, {keyword: carname, type : “top”}, function(data){}, “json”)向上诉的Serlvet发起post请求,post的第一个参数是Serlvet的后台地址,第二个参数画括号括起来的json数据,第三个参数是回调函数,第四个参数”json”表明发送的json数据。在回调函数中,参数data接收Serlvet返回的值,由于Serlvet返回的是可以解析为字符串数组的数据,所以用for循环来遍历得到的数据,并生成option新节点appenTo()插入到select之后。

程序清单1.8中,值得注意的地方还有$(“.loading”).ajaxStart(function(){}).ajaxStop(function(){}),这是为了美化汽车图片加载的代码。这里用到jQuery的动画专用效果的animate(),使程序淡入淡出更加的和谐。

到此几乎把级联效果实现了,但是如果在高并发环境下,每次用户切换选项都向服务器发送请求,服务器的压力可能过大。所以这里我们用jQuery的缓存来保存那些已经缓存过的请求。可以使用jQuery的data()方法。

定义和用法

从被选元素中返回附加的数据。

$(selector).data(name)

name 可选。规定要取回的数据的名称。
如果没有规定名称,则该方法将以对象的形式从元素中返回所有存储的数据。

向元素附加数据

$(selector).data(name,value)

name 必需。规定要设置的数据的名称。
value 必需。规定要设置的数据的值。
data()的使用案例如程序清单1.9:

<html>
<head>
<script type="text/javascript" src="/jquery/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
 $("#btn1").click(function(){
 $("div").data("greeting", "Hello World");
 });
 $("#btn2").click(function(){
 alert($("div").data("greeting"));
 });
});
</script>
</head>
<body>
<button id="btn1">把数据添加到 div 元素</button><br />
<button id="btn2">获取已添加到 div 元素的数据</button>
<div></div>
</body>
</html>

加上缓存之后的完整jQuery代码如下程序清单。
程序清单2.0:chainSelect.js

/**
 * 级联下拉框效果
 */

$(document).ready(function(){
 //找到三个下拉框
 var carnameSelect = $(".carname").children("select");
 var cartypeSelect = $(".cartype").children("select");
 var wheeltypeSelect = $(".wheeltype").children("select");

 carnameSelect.change(function(){
 var carname = carnameSelect.val();
 if(carname != "") {
 if (!carnameSelect.data(carname)) {
 //汽车厂商不为空发起ajax请求
 $.post("../chainSelect", {keyword: carname, type : "top"}, function(data){
  if(data != null && data.length != 0) {
  //清除上一次change的内容
  cartypeSelect.html("");
  $("<option value=''>请选择汽车类型</option>").appendTo(cartypeSelect);
  for(var i = 0; i < data.length; i++) {
  $("<option value='"+data[i]+"'>"+data[i]+"</option>").appendTo(cartypeSelect);
  }
  $(".cartype").show();
  carnameSelect.next("img").show();
  }
  //将data放入缓存
  carnameSelect.data(carname, data);
 }, "json");
 } else {
 //从缓存中取出数据
 var data = carnameSelect.data(carname);
 if(data != null && data.length != 0) {
  //清除上一次change的内容
  cartypeSelect.html("");
  $("<option value=''>请选择汽车类型</option>").appendTo(cartypeSelect);
  for(var i = 0; i < data.length; i++) {
  $("<option value='"+data[i]+"'>"+data[i]+"</option>").appendTo(cartypeSelect);
  }
  $(".cartype").show();
  carnameSelect.next("img").show();
 }
 }
 } else {
 //3.如果值为空,那么第二个下拉框所在span要隐藏起来,第一个下拉框后面的指示图片也要隐藏
 $(".cartype").hide();
 $(".wheeltype").hide();
 $(".carimage").hide();
 $(this).next("img").hide();
 }
 });

 cartypeSelect.change(function(){
 var cartype = cartypeSelect.val();
 if(cartype != "") {
 if(!cartypeSelect.data(cartype)) {
 //汽车类型不为空发起ajax请求
 $.post("../chainSelect", {keyword: cartype, type : "sub"}, function(data){
  if(data != null && data.length != 0) {
  //清除上一次change的内容
  wheeltypeSelect.html("");
  $("<option value=''>请选择车轮类型</option>").appendTo(wheeltypeSelect);
  for(var i = 0; i < data.length; i++) {
  $("<option value='"+data[i]+"'>"+data[i]+"</option>").appendTo(wheeltypeSelect);
  }
  $(".wheeltype").show();
  cartypeSelect.next("img").show();
  }
  cartypeSelect.data(cartype, data);
 }, "json");
 } else {
 var data = cartypeSelect.data(cartype);
 if(data != null && data.length != 0) {
  //清除上一次change的内容
  wheeltypeSelect.html("");
  $("<option value=''>请选择车轮类型</option>").appendTo(wheeltypeSelect);
  for(var i = 0; i < data.length; i++) {
  $("<option value='"+data[i]+"'>"+data[i]+"</option>").appendTo(wheeltypeSelect);
  }
  $(".wheeltype").show();
  cartypeSelect.next("img").show();
 }
 }
 } else {
 //汽车类型为空
 $(".wheeltype").hide();
 $(".carimage").hide();
 $(this).next("img").hide();
 } 
 });

 wheeltypeSelect.change(function(){
 //选中的车轮类型
 var wheeltype = wheeltypeSelect.val(); 
 if(wheeltype != "") {
 //选中的车辆厂商
 var carname = carnameSelect.val();
 //选中的车辆类型
 var cartype = cartypeSelect.val();

 //图片的名称
 var carimgName = carname + "_" + cartype + "_" + wheeltype + ".jpg";

 $(".carimage").show(); 
 //通过Javascript中的Image对象预装载图片
 var cacheimg = new Image();
 $(cacheimg).attr("src", "../image/" + carimgName).load(function(){
 //隐藏loading图片
 $(".carloading").hide("slow");
 $(".carimg").attr("src", "../image/" + carimgName);
 });


 $(".carimage p img").show("slow");
 } else {
 $(".carimage").hide();
 }
 });

 //给数据装载中的节点定义ajax事件,实现动画提示效果
 $(".loading").ajaxStart(function(){
 $(this).css("visibility", "visible");
 $(this).animate({
 opacity: 1
 },0);
 }).ajaxStop(function(){
 $(this).animate({
 opacity: 0
 },500);
 });
});

用了data()之后,当用户选择了下拉框,并不是直接奔着服务器请求而去的,而是先判断缓存是否为空,carnameSelect.data(carname)。如果为空,则发起ajax请求,并将返回的结果放进缓存carnameSelect.data(carname, data)。如果不为空,在循环添加option节点之前data从缓存中拿到var data = carnameSelect.data(carname)。同样的,图片的缓存放进我们的Image对象中var cacheimg = new Image(),这行代码往后的第一行和第四行将缓存中的图片取出并显示出来。

代码下载地址:https://github.com/shizongger/JqueryInAction

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 弹出窗口中是否显示地址栏的实现代码
Apr 14 Javascript
幻灯片带网页设计中的20个奇妙应用示例小结
May 27 Javascript
jQuery隔行变色与普通JS写法的对比
Apr 21 Javascript
js中hash和ico的关联分析
Feb 05 Javascript
javascript中attachEvent用法实例分析
May 14 Javascript
JQuery中节点遍历方法实例
May 18 Javascript
自定义Angular指令与jQuery实现的Bootstrap风格数据双向绑定的单选与多选下拉框
Dec 12 Javascript
简介EasyUI datagrid editor combogrid搜索框的实现
Apr 01 Javascript
JavaScript中的call和apply的用途以及区别
Jan 11 Javascript
简单谈谈原生js的math对象
Jun 27 Javascript
extjs简介_动力节点Java学院整理
Jul 17 Javascript
浅谈Vue 初始化性能优化
Aug 31 Javascript
webpack入门+react环境配置
Feb 08 #Javascript
JavaScript实现鼠标点击导航栏变色特效
Feb 08 #Javascript
jQuery实现优雅的弹窗效果(6)
Feb 08 #Javascript
JavaScript中的子窗口与父窗口的互相调用问题
Feb 08 #Javascript
深入理解js中的加载事件
Feb 08 #Javascript
滚动条的监听与内容随着滚动条动态加载的实现
Feb 08 #Javascript
JQuery页面随滚动条动态加载效果的简单实现(推荐)
Feb 08 #Javascript
You might like
windows下配置apache+php+mysql时出现问题的处理方法
2014/06/20 PHP
PHP简单实现防止SQL注入的方法
2018/03/13 PHP
PHP等比例压缩图片的实例代码
2018/07/26 PHP
PHP htmlspecialchars() 函数实例代码及用法大全
2018/09/18 PHP
对laravel的csrf 防御机制详解,及form中csrf_token()的存在介绍
2019/10/24 PHP
JavaScript中的prototype使用说明
2010/04/13 Javascript
Javascript中产生固定结果的函数优化技巧
2013/01/16 Javascript
VS2008中使用JavaScript调用WebServices
2014/12/18 Javascript
Jquery 实现图片轮换
2015/01/28 Javascript
实例详解ECMAScript5中新增的Array方法
2016/04/05 Javascript
Jquery为DIV添加click事件的简单实例
2016/06/02 Javascript
JavaScript函数中关于valueOf和toString的理解
2016/06/14 Javascript
javascript 秒表计时器实现代码
2017/03/09 Javascript
JavaScript中七种流行的开源机器学习框架
2018/10/11 Javascript
12 种使用Vue 的最佳做法
2020/03/30 Javascript
JS使用for in有序获取对象数据
2020/05/19 Javascript
JavaScript常用8种数组去重代码实例
2020/09/09 Javascript
Vue this.$router.push(参数)实现页面跳转操作
2020/09/09 Javascript
[06:53]2018DOTA2国际邀请赛寻真——为复仇而来的Newbee
2018/08/15 DOTA
Python 性能优化技巧总结
2016/11/01 Python
利用pyinstaller或virtualenv将python程序打包详解
2017/03/22 Python
Python使用修饰器执行函数的参数检查功能示例
2017/09/26 Python
Python3 串口接收与发送16进制数据包的实例
2019/06/12 Python
使用Python的turtle模块画国旗
2019/09/24 Python
python 申请内存空间,用于创建多维数组的实例
2019/12/02 Python
python 装饰器的实际作用有哪些
2020/09/07 Python
matplotlib源码解析标题实现(窗口标题,标题,子图标题不同之间的差异)
2021/02/22 Python
欧洲领先的技术商店:eibmarkt.com
2019/05/10 全球购物
技校生自我鉴定
2013/12/08 职场文书
关于梦想的演讲稿
2014/05/05 职场文书
2014年党风廉政工作总结
2014/12/03 职场文书
2015年世界艾滋病日活动总结
2015/03/24 职场文书
民事答辩状格式范文
2015/05/21 职场文书
军训决心书范文
2015/09/22 职场文书
有关保护环境的宣传标语100条
2019/08/07 职场文书
《狼王梦》读后感:可怜天下父母心
2019/11/01 职场文书