本来想用jquery的autocomplete的,可是需求有些变化,打算改源码,进了源码发现,改起来要的时间太长了,毕竟不是自己写的,改起来慢,在网上开始大肆搜罗资料,终于找到了类似的

本文转自http://www.cnblogs.com/jaiho/archive/2011/02/28/js_autocomplete.html

完成有以下功能:

  • 输入字符会把以输入字符开头的提示出来。
  • 支持上下方向键选择提示选项,支持循环
  • 支持绑定一个数组提示,支持ajax传递输入框值请求数据。
  • 支持多个选择的dom元素一块绑定数据实现输入提示。各dom元素也可以单独绑定自己的数据实现输入提示,互不影响。
  • 支持中文。

首先是js的核心部分,其各部分都有较详细的说明,代码如下:

; (function (window) {/* 插件开始 */var autoComplete = function (o) {var handler = (function () {var handler = function (e, o) { return new handler.prototype.init(e, o); };/* 为每个选择的dom都创建一个相对应的对象,这样选择多个dom时可以很方便地使用 */handler.prototype = {e: null, o: null, timer: null, show: 0, input: null, popup: null,init: function (e, o) {/* 设置初始对象 */this.e = e, this.o = o,this.input = this.e.getElementsByTagName(this.o.input)[0],this.popup = this.e.getElementsByTagName(this.o.popup)[0],this.initEvent();/* 初始化各种事件 */},match: function (quickExpr, value, source) {/* 生成提示 */var li = null;for (var i in source) {if (value.length > 0 && quickExpr.exec(source[i]) != null) {li = document.createElement('li');li.innerHTML = '<a href="javascript:;">' + source[i] + '</a>';this.popup.appendChild(li);}}if (this.popup.getElementsByTagName('a').length)this.popup.style.display = 'block';elsethis.popup.style.display = 'none';},ajax: function (type, url, quickExpr, search) {/* ajax请求远程数据 */var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();xhr.open(type, url, true);/* 同异步在此修改 */xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");var that = this;xhr.onreadystatechange = function () {if (xhr.readyState == 4) {if (xhr.status == 200) {var data = eval(xhr.responseText);that.match(quickExpr, search, data);/* 相同于成功的回调函数 */} else {alert("请求页面异常!");/* 请求失败 */}}};xhr.send(null);},fetch: function (ajax, search, quickExpr) {search = encodeURI(search);/* 解决ie中文乱码 */var that = this;this.ajax(ajax.type, ajax.url + search, quickExpr, search);},initEvent: function () {/* 各事件的集合 */var that = this;this.input.onfocus = function () {if (this.inputValue) this.value = this.inputValue;var value = this.value, quickExpr = RegExp('^' + value, 'i'), self = this;var els = that.popup.getElementsByTagName('a');if (els.length > 0) that.popup.style.display = 'block';that.timer = setInterval(function () {if (value != self.value) {/* 判断输入内容是否改变,兼容中文 */value = self.value;that.popup.innerHTML = '';if (value != '') {quickExpr = RegExp('^' + value);if (that.o.source) that.match(quickExpr, value, that.o.source);else if (that.o.ajax) that.fetch(that.o.ajax, value, quickExpr);}}}, 200);};this.input.onblur = function () {/*  输入框添加事件 */if (this.value != this.defaultValue) this.inputValue = this.value;clearInterval(that.timer);var current = -1;/* 记住当前有焦点的选项 */var els = that.popup.getElementsByTagName('a');var len = els.length - 1;var aClick = function () {that.input.inputValue = this.firstChild.nodeValue;that.popup.innerHTML = '';that.popup.style.display = 'none';that.input.focus();};var aFocus = function () {for (var i = len; i >= 0; i--) {if (this.parentNode === that.popup.children[i]) {current = i;break;}}//that.input.value = this.firstChild.nodeValue;for (var k in that.o.elemCSS.focus) {this.style[k] = that.o.elemCSS.focus[k];}};var aBlur = function () {for (var k in that.o.elemCSS.blur)this.style[k] = that.o.elemCSS.blur[k];};var aKeydown = function (event) {event = event || window.event;/* 兼容IE */if (current === len && event.keyCode === 9) {/* tab键时popup隐藏 */that.popup.style.display = 'none';} else if (event.keyCode == 40) {/* 处理上下方向键事件方便选择提示的选项 */current++;if (current < -1) current = len;if (current > len) {current = -1;that.input.focus();} else {that.popup.getElementsByTagName('a')[current].focus();}} else if (event.keyCode == 38) {current--;if (current == -1) {that.input.focus();} else if (current < -1) {current = len;that.popup.getElementsByTagName('a')[current].focus();} else {that.popup.getElementsByTagName('a')[current].focus();}}};for (var i = 0; i < els.length; i++) {/* 为每个选项添加事件 */els[i].onclick = aClick;els[i].onfocus = aFocus;els[i].onblur = aBlur;els[i].onkeydown = aKeydown;}};this.input.onkeydown = function (event) {event = event || window.event;/* 兼容IE */var els = that.popup.getElementsByTagName('a');if (event.keyCode == 40) {if (els[0]) els[0].focus();} else if (event.keyCode == 38) {if (els[els.length - 1]) els[els.length - 1].focus();} else if (event.keyCode == 9) {if (event.shiftKey == true) that.popup.style.display = 'none';}};this.e.onmouseover = function () { that.show = 1; };this.e.onmouseout = function () { that.show = 0; };addEvent.call(document, 'click', function () {if (that.show == 0) {that.popup.style.display = 'none';}});/* 处理提示框dom元素不支持onblur的情况 */}};handler.prototype.init.prototype = handler.prototype;/* JQuery style,这样我们在处的时候就不用每个dom元素都用new来创建对象了 */return handler;/* 把内部的处理函数传到外部 */})();if (this.length) {/* 处理选择多个dom元素 */for (var a = this.length - 1; a >= 0; a--) {/* 调用方法为每个选择的dom生成一个处理对象,使它们不互相影响 */handler(this[a], o);}} else {/* 处理选择一个dom元素 */handler(this, o);}return this;};return window.autoComplete = autoComplete;/* 暴露方法给全局对象 *//* 插件结束 */
})(window);

  其中了一些全局的自定义函数,如addEvent和在例子中将要用到的getElementsByClassName函数如下:

var getElementsByClassName = function (searchClass, node, tag) {/* 兼容各浏览器的选择class的方法;(写法参考了博客园:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1529640.html,想了解更多请看这个地址) */node = node || document, tag = tag ? tag.toUpperCase() : "*";if (document.getElementsByClassName) {/* 支持getElementsByClassName的浏览器 */var temp = node.getElementsByClassName(searchClass);if (tag == "*") {return temp;} else {var ret = new Array();for (var i = 0; i < temp.length; i++)if (temp[i].nodeName == tag)ret.push(temp[i]);return ret;}} else {/* 不支持getElementsByClassName的浏览器 */var classes = searchClass.split(" "),elements = (tag === "*" && node.all) ? node.all : node.getElementsByTagName(tag),patterns = [], returnElements = [], current, match;var i = classes.length;while (--i >= 0)patterns.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)"));var j = elements.length;while (--j >= 0) {current = elements[j], match = false;for (var k = 0, kl = patterns.length; k < kl; k++) {match = patterns[k].test(current.className);if (!match) break;}if (match) returnElements.push(current);}return returnElements;}
};
var addEvent = (function () {/* 用此函数添加事件防止事件覆盖 */if (document.addEventListener) {return function (type, fn) { this.addEventListener(type, fn, false); };} else if (document.attachEvent) {return function (type, fn) {this.attachEvent('on' + type, function () {return fn.call(this, window.event);/* 兼容IE */});};}
})();

  最后是调用的部分,调用和每个参数的部分都有说明和注意事项,再说一个其中source和ajax参数是二选一,如果二者都写只有source是有用的,调用代码如下:

addEvent.call(null,'load',function(){autoComplete.call( getElementsByClassName('autoComplete'), {/* 使用call或apply调用此方法 */source:['0123','023',123,1234,212,214,'033333','0352342',1987,17563,20932],/* 提示时在此数组中搜索 *///ajax:{ type:'post',url:'./php/fetch.php?search=' },/* 如果使用ajax则返回的数据格式要与source相同,如为字符串"[111,222,333,444]"等形式。*/elemCSS:{ focus:{'color':'#00ff00','background':'red'}, blur:{'color':'#ff0000','background':'transparent'} },/* 些对象中的key要js对象中的style属性支持 */input:'input',/* 输入框使用input元素 */popup:'ul'/* 提示框使用ul元素 */});
});

完整的调用示例

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>autoComplete</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css"> .autoComplete {margin:8px;position:relative;float:left;} .autoComplete input {width:200px;height:25px;margin:0;padding:0;line-height:25px;} .autoComplete ul {z-index:-12;padding:0px;margin:0px;border:1px #333 solid;width:200px;background:white;display:none;position:absolute;left:0;top:28px;*margin-left:9px;*margin-top:2px;margin-top:1px\0;} .autoComplete li {list-style:none;} .autoComplete li a {display:block;color:#000;text-decoration:none;padding:1px 0 1px 5px;_width:97%;} .autoComplete li a:hover {color:#000;background:#ccc;border:none;} </style> <script type="text/javascript"> //<![CDATA[ var getElementsByClassName = function (searchClass, node, tag) {/* 兼容各浏览器的选择class的方法;(写法参考了博客园:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1529640.html,想了解更多请看这个地址) */ node = node || document, tag = tag ? tag.toUpperCase() : "*"; if(document.getElementsByClassName){/* 支持getElementsByClassName的浏览器 */ var temp = node.getElementsByClassName(searchClass); if(tag=="*"){ return temp; } else { var ret = new Array(); for(var i=0; i<temp.length; i++) if(temp[i].nodeName==tag) ret.push(temp[i]); return ret; } }else{/* 不支持getElementsByClassName的浏览器 */ var classes = searchClass.split(" "), elements = (tag === "*" && node.all)? node.all : node.getElementsByTagName(tag), patterns = [], returnElements = [], current, match; var i = classes.length; while(--i >= 0) patterns.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)")); var j = elements.length; while(--j >= 0){ current = elements[j], match = false; for(var k=0, kl=patterns.length; k<kl; k++){ match = patterns[k].test(current.className); if(!match) break; } if(match) returnElements.push(current); } return returnElements; } }; var addEvent=(function(){/* 用此函数添加事件防止事件覆盖 */ if(document.addEventListener){ return function(type, fn){ this.addEventListener(type, fn, false); }; }else if(document.attachEvent){ return function(type,fn){ this.attachEvent('on'+type, function () { return fn.call(this, window.event);/* 兼容IE */ }); }; } })(); ;(function(window){ /* 插件开始 */ var autoComplete=function(o){ var handler=(function(){ var handler=function(e,o){ return new handler.prototype.init(e,o); };/* 为每个选择的dom都创建一个相对应的对象,这样选择多个dom时可以很方便地使用 */ handler.prototype={ e:null, o:null, timer:null, show:0, input:null, popup:null, init:function(e,o){/* 设置初始对象 */ this.e=e, this.o=o, this.input=this.e.getElementsByTagName(this.o.input)[0], this.popup=this.e.getElementsByTagName(this.o.popup)[0], this.initEvent();/* 初始化各种事件 */ }, match:function(quickExpr,value,source){/* 生成提示 */ var li = null; for(var i in source){ if( value.length>0 && quickExpr.exec(source[i])!=null ){ li = document.createElement('li'); li.innerHTML = '<a href="javascript:;">'+source[i]+'</a>'; this.popup.appendChild(li); } } if(this.popup.getElementsByTagName('a').length) this.popup.style.display='block'; else this.popup.style.display='none'; }, ajax:function(type,url,quickExpr,search){/* ajax请求远程数据 */ var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); xhr.open(type,url,true);/* 同异步在此修改 */ xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var that=this; xhr.onreadystatechange = function(){ if(xhr.readyState==4) { if(xhr.status==200) { var data = eval(xhr.responseText); that.match(quickExpr,search,data);/* 相同于成功的回调函数 */ }else{ alert("请求页面异常!");/* 请求失败 */ } } }; xhr.send(null); }, fetch:function(ajax,search,quickExpr){ search = encodeURI(search);/* 解决ie中文乱码 */ var that=this; this.ajax(ajax.type,ajax.url+search,quickExpr,search); }, initEvent:function(){/* 各事件的集合 */ var that=this; this.input.onfocus = function(){ if(this.inputValue) this.value = this.inputValue; var value=this.value, quickExpr=RegExp('^'+value,'i'), self=this; var els = that.popup.getElementsByTagName('a'); if(els.length>0) that.popup.style.display = 'block'; that.timer=setInterval(function(){ if(value!=self.value){/* 判断输入内容是否改变,兼容中文 */ value=self.value; that.popup.innerHTML=''; if(value!=''){ quickExpr=RegExp('^'+value); if(that.o.source) that.match(quickExpr,value,that.o.source); else if(that.o.ajax) that.fetch(that.o.ajax,value,quickExpr); } } },200); }; this.input.onblur = function(){/* 输入框添加事件 */ if(this.value!=this.defaultValue) this.inputValue = this.value; clearInterval(that.timer); var current=-1;/* 记住当前有焦点的选项 */ var els = that.popup.getElementsByTagName('a'); var len = els.length-1; var aClick = function(){ that.input.inputValue = this.firstChild.nodeValue; that.popup.innerHTML=''; that.popup.style.display='none'; that.input.focus(); }; var aFocus = function(){ for(var i=len; i>=0; i--){ if(this.parentNode===that.popup.children[i]){ current = i; break; } } //that.input.value = this.firstChild.nodeValue; for(var k in that.o.elemCSS.focus){ this.style[k] = that.o.elemCSS.focus[k]; } }; var aBlur= function(){ for(var k in that.o.elemCSS.blur) this.style[k] = that.o.elemCSS.blur[k]; }; var aKeydown = function(event){ event = event || window.event;/* 兼容IE */ if(current === len && event.keyCode===9){/* tab键时popup隐藏 */ that.popup.style.display = 'none'; }else if(event.keyCode==40){/* 处理上下方向键事件方便选择提示的选项 */ current++; if(current<-1) current=len; if(current>len){ current=-1; that.input.focus(); }else{ that.popup.getElementsByTagName('a')[current].focus(); } }else if(event.keyCode==38){ current--; if(current==-1){ that.input.focus(); }else if(current<-1){ current = len; that.popup.getElementsByTagName('a')[current].focus(); }else{ that.popup.getElementsByTagName('a')[current].focus(); } } }; for(var i=0; i<els.length; i++){/* 为每个选项添加事件 */ els[i].onclick = aClick; els[i].onfocus = aFocus; els[i].onblur = aBlur; els[i].onkeydown = aKeydown; } }; this.input.onkeydown = function(event){ event = event || window.event;/* 兼容IE */ var els = that.popup.getElementsByTagName('a'); if(event.keyCode==40){ if(els[0]) els[0].focus(); }else if(event.keyCode==38){ if(els[els.length-1]) els[els.length-1].focus(); }else if(event.keyCode==9){ if(event.shiftKey==true) that.popup.style.display = 'none'; } }; this.e.onmouseover = function(){ that.show=1; }; this.e.onmouseout = function(){ that.show=0; }; addEvent.call(document,'click',function(){ if(that.show==0){ that.popup.style.display='none'; } });/* 处理提示框dom元素不支持onblur的情况 */ } }; handler.prototype.init.prototype=handler.prototype;/* JQuery style,这样我们在处的时候就不用每个dom元素都用new来创建对象了 */ return handler;/* 把内部的处理函数传到外部 */ })(); if(this.length){/* 处理选择多个dom元素 */ for(var a=this.length-1; a>=0; a--){/* 调用方法为每个选择的dom生成一个处理对象,使它们不互相影响 */ handler(this[a],o); } }else{/* 处理选择一个dom元素 */ handler(this,o); } return this; }; return window.autoComplete = autoComplete;/* 暴露方法给全局对象 */ /* 插件结束 */ })(window); /* 调用 */ addEvent.call(null,'load',function(){ autoComplete.call( getElementsByClassName('autoComplete'), {/* 使用call或apply调用此方法 */ source:['0123','023',123,1234,212,214,'033333','0352342',1987,17563,20932],/* 提示时在此数组中搜索 */ //ajax:{ type:'post',url:'./php/fetch.php?search=' },/* 如果使用ajax则远程返回的数据格式要与source相同 */ elemCSS:{ focus:{'color':'black','background':'#ccc'}, blur:{'color':'black','background':'transparent'} },/* 些对象中的key要js对象中的style属性支持 */ input:'input',/* 输入框使用input元素 */ popup:'ul'/* 提示框使用ul元素 */ }); }); //]]> </script> </head> <body><!-- 这所以使用这么多的z-index是因为ie6和ie7的问题 --> <div> <div class="autoComplete" style="z-index:19"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:18"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:17"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:16"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:15"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:14"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:13"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:12"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:11"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:10"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:9"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:8"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:7"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:6"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:5"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:4"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:3"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:2"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:1"> <input value="input" /> <ul><li></li></ul> </div> <div class="autoComplete" style="z-index:0"> <input value="input" /> <ul><li></li></ul> </div> <div style="clear:both;"></div> </div> <div style="border:3px red double;margin:15px;padding:5px;"> <h3 style="line-height:10px;">Tip:</h3> <ul> <li>输入0、1,2会得到提示。</li> <li>用鼠标或上下键可以选择提示。</li> <li>选择点击鼠标或点回车可以选择选项。</li> <li>可以修改调用处,使各个输入框提示不同内容。</li> </ul> </div> </body> </html>

转载于:https://www.cnblogs.com/meitangdekafei/p/4166857.html

原生js自动完成 [转]相关推荐

  1. js 自动分配金额_(2.4w字,建议收藏)??原生JS灵魂之问(下), 冲刺??进阶最后一公里(附个人成长经验分享)

    笔者最近在对原生JS的知识做系统梳理,因为我觉得JS作为前端工程师的根本技术,学再多遍都不为过.打算来做一个系列,一共分三次发,以一系列的问题为驱动,当然也会有追问和扩展,内容系统且完整,对初中级选手 ...

  2. 原生JS制作自动+手动轮播图,附带二级分类菜单

    原生JS制作自动+手动轮播图,附带二级分类菜单 包含以下功能: 1.鼠标移开自动轮播 2.鼠标移入停止自动轮播 3.点击左右按钮可手动切换图片 4.点击索引小圆点可手动切换图片 5.鼠标移入一级菜单展 ...

  3. js map遍历 修改对象里面的值_求职季之你必须要懂的原生JS(上)

    点击上方"IT平头哥联盟",选择"置顶或者星标" 一起进步- 互联网寒冬之际,各大公司都缩减了HC,甚至是采取了"裁员"措施,在这样的大环境 ...

  4. 原生js实现Ajax,JSONP

    Ajax内部的几个执行步骤 创建XMLHttpRequest对象(new XMLHttpRequest()) 设置请求头(setRequestHeader) 连接服务器(open()) 设置回调(on ...

  5. 原生js实现轮播图实例教程

    原生js实现轮播图实例教程 本实例效果如下图所示: 根据实例效果,需要的元素有图片.中间圆点按钮.左右箭头按钮等.实际html代码如下所示: <div class="banner_co ...

  6. vue如何使用原生js写动画效果_原生js写一个无缝轮播图插件(支持vue)

    轮播图插件(Broadcast.js) 前言:写这个插件的原因 前段时间准备用vue加上网易云的nodejs接口,模拟网易云音乐移动端.因为想自己写一遍所有的代码以及加固自己的flex布局,所以没有使 ...

  7. AJAX请求和跨域请求详解(原生JS、Jquery)

    一.概述 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. AJAX = 异步 JavaScript 和 XML,是一种用于创建快速动态网页的技术.通过在后台与服务器进行少量数 ...

  8. dw按钮图片滚动js_轮播图--swiper插件/原生js/jQuery

    1.swiper插件: 需要下载该插件到本地,并用link标签引用其swiper-bundle.min.css文件,用script引用其swiper-bundle.min.js文件,下载地址及官方文档 ...

  9. AJAX初识(原生JS版AJAX和Jquery版AJAX)

    一.什么是JSON 1.介绍JSON独立于语言,是一种与语言无关的数据格式.JSON指的是JavaScript对象表示法(JavaScript Object Notation)JSON是轻量级的文本数 ...

最新文章

  1. 币未来趋势分析_分析:中国便利店零售市场现状以及未来发展趋势
  2. vue创建脚手架 cil
  3. 关于我转生变成史莱姆这档事
  4. 第十四天:规划质量管理,一致性成本、非一致性成本、质量七工具
  5. 【转】logback 常用配置详解(序)logback 简介
  6. Mapreduce执行过程分析(基于Hadoop2.4)——(一)
  7. 华为usg6000配置手册_带你了解防火墙安全区域的作用及简单的配置,小白不要错过了...
  8. 【Python】文件夹的常用操作
  9. 跨链协议 ChainSwap 将于今晚 9 点在 Uniswap 上进行代币 TOKEN 的 LBP
  10. C++中new和delete来创建和释放动态数组
  11. Android系统QFIL刷机流程
  12. 按键精灵打怪学习-自动寻路回打怪点
  13. 【单目测距和双目测距比较】
  14. 阿里巴巴编码规范习题
  15. 今日头条 推荐机制实现
  16. Table 组件构建过程中遇到的问题与解决思路
  17. 动图如何在线制作?教你一键在线制作动图
  18. 视觉打标软件 在线视觉打标系统 1.金橙子控制板卡 2.自主研发的定位系统
  19. android ui设计 知乎,界面设计进化!知乎日报2.0新版发布下载
  20. BootLoader是什么 转载至百度百科

热门文章

  1. VSCode 安装 Go 插件、gopls 是个什么东东
  2. Python 中的魔术方法(双下划线开头和结尾的方法)
  3. etcd 笔记(09)— 基于 etcd 实现微服务的注册与发现
  4. c/c++ 如何输入带空格的字符串
  5. pytorch方法,Tensor及其基本操作_重点
  6. Pandas库常用函数和操作
  7. Tesla Model汽车架构与FSD供应链
  8. Arm Cortex-M3 MCU性能
  9. 薄膜封装,等离子体技术,原子层沉积,化学气相沉积
  10. Docker核心技术之数据管理