当前位置: 首页 > news >正文

建网站公建网站公司个人网站怎样申请

建网站公建网站公司,个人网站怎样申请,岳阳建站公司,深圳龙华区高峰社区前些天发现了一个巨牛的人工智能学习网站#xff0c;通俗易懂#xff0c;风趣幽默#xff0c;忍不住分享一下给大家。点击跳转到教程。 话说HTML5的炫酷真的是让我爱不释手#xff0c;即使在这个提到IE就伤心不完的年代。但话又说回来#xff0c;追求卓越Web创造更美世界…前些天发现了一个巨牛的人工智能学习网站通俗易懂风趣幽默忍不住分享一下给大家。点击跳转到教程。 话说HTML5的炫酷真的是让我爱不释手即使在这个提到IE就伤心不完的年代。但话又说回来追求卓越Web创造更美世界这样高的追求什么时候又与IE沾过边儿呢所以当你在看本文并且我们开始讨论HTML5等前沿东西的时候我们默认是把IE排除在外的。本文的例子可以工作在最新的Chrome及Firefox浏览器下其他浏览器暂未测试。 // 若下方未出现演示页面请刷新。 你也可以点此全屏演示  或者前往GitHub进行代码下载然后本地运行。 你还可以 下载示例音乐如果你手头没有音频文件的话 文件列表 bbc_sherlock_openning.mp3 Neptune Illusion Dennis Kuo .mp3 单曲Remix ┃ 爱上这个女声 放进专辑里私藏 夜电播音员.mp3 爱啦啦.mp3 最后喜欢的朋友可以去GitHub星我(star me)叉我(fork me)。 这里将要介绍的HTML5 音频处理接口与Audio标签是不一样的。页面上的Audio标签只是HTML5更语义化的一个表现而HTML5提供给JavaScript编程用的Audio API则让我们有能力在代码中直接操作原始的音频流数据对其进行任意加工再造。 展示HTML5 Audio API 最典型直观的一个例子就是跟随音乐节奏变化的频谱图也称之为可视化效果。本文便是以此为例子展示JavaScript中操作音频数据的。 文中代码仅供参考实际代码以下载的源码为准。 了解Audio API 一段音频到达扬声器进行播放之前半路对其进行拦截于是我们就得到了音频数据了这个拦截工作是由window.AudioContext来做的我们所有对音频的操作都基于这个对象。通过AudioContext可以创建不同各类的AudioNode即音频节点不同节点作用不同有的对音频加上滤镜比如提高音色(比如BiquadFilterNode)改变单调有的音频进行分割比如将音源中的声道分割出来得到左右声道的声音ChannelSplitterNode有的对音频数据进行频谱分析即本文要用到的(AnalyserNode)。 浏览器中的Audio API 统一前缀 JavaScript中处理音频首先需要实例化一个音频上下文类型window.AudioContext。目前Chrome和Firefox对其提供了支持但需要相应前缀Chrome中为window.webkitAudioContextFirefox中为mozAudioContext。所以为了让代码更通用能够同时工作在两种浏览器中只需要一句代码将前缀进行统一即可。 window.AudioContext window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; 这是一种常见的用法或者操作符|| 连接起来的表达式中遇到真值即返回。比如在Chrome中window.AudioContext为undefined接着往下走碰到window.webkitAudioContext不为undefined表达式在此判断为真值所以将其返回于是此时window.AudioContext window.webkitAudioContext 所以代码中我们就可以直接使用window.AudioContext 而不用担心具体Chrome还是Firefox了。 var audioContextnew window.AudioContext(); 考虑浏览器不支持的情况 但这还只是保证了在支持AudioContext的浏览器中能正常工作如果是在IE中上面实例化对象的操作会失败所以有必要加个try catch语句来避免报错。 try {var audioContext new window.AudioContext(); } catch (e) {Console.log(!Your browser does not support AudioContext); } 这样就安全多啦妈妈再不担心浏览器报错了。 组织代码 为了更好地进行编码我们创建一个Visualizer对象把所有相关属性及方法写到其中。按照惯例对象的属性直接写在构造器里面对象的方法写到原型中。对象内部使用的私有方法以短横线开头不是必要但是种好的命名习惯。 其中设置了一些基本的属性将在后续代码中使用详细的还请参见源码这里只简单展示。 var Visualizer function() {this.file null, //要处理的文件后面会讲解如何获取文件this.fileName null, //要处理的文件的名文件名this.audioContext null, //进行音频处理的上下文稍后会进行初始化this.source null, //保存音频 }; Visualizer.prototype {_prepareAPI: function() {//统一前缀方便调用window.AudioContext window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;//这里顺便也将requestAnimationFrame也打个补丁后面用来写动画要用window.requestAnimationFrame window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame;//安全地实例化一个AudioContext并赋值到Visualizer的audioContext属性上方便后面处理音频使用try {this.audioContext new AudioContext();} catch (e) {console.log(!妳的浏览器不支持AudioContext:();console.log(e);}}, } 加载音频文件 不用说你肯定得先在代码中获取到音频文件才能够对其进一步加工。 文件获取的方法 读取文件到JavaScript可以有以下三种方法 1.新开一个Ajax异步请求来获取文件如果是本地测试需要关掉浏览器的同源安全策略才能获取成功不然只能把网页放到服务器上才能正常工作。 具体说来就是先开一个XMLHttpRequest请求将文件路径作为请求的URL并且设置请求返回类型为ArrayBuffer这种格式方便我们后续的处理。下面是一个例子。 loadSound(sample.mp3); //调用 // 定义加载音频文件的函数 function loadSound(url) {var request new XMLHttpRequest(); //建立一个请求request.open(GET, url, true); //配置好请求类型文件路径等request.responseType arraybuffer; //配置数据返回类型// 一旦获取完成对音频进行进一步操作比如解码request.onload function() {var arraybuffer request.response;}request.send(); } 2.通过文件类型的input来进行文件选择监听input的onchnage事件一担文件选中便开始在代码中进行获取处理此法方便且不需要工作在服务器上 3.通过拖拽的形式把文件拖放到页面进行获取比前面一种方法稍微繁杂一点要监听dragenter,dragover,drop等事件但同样可以很好地在本地环境下工作无需服务器支持。 更多在JavaScript中获取及处理文件的方法可以见这里 不用说方法2和3方便本地开发与测试所以我们两种方法都实现既支持选择文件也支持文件拖拽。 通过选择获取 在页面放一个file类型的input。然后在JavaScript中监听它的onchange事件。此事件在input的值发生变化时触发。 对于onchange事件在Chrome与Firefox中还有一点小的区别如果你已经选择了一个文件此时Input就有值了如果你再次选择同一文件onchange事件不会触发但在Firefox中该事件会触发。这里只是提及一下关系不大。 label foruploadedFileDragdrop or select a file to play:/label input typefile iduploadedFile/input 当然这里同时也把最后我们要画图用的canvas也一起放上去吧后面就不用多话了。所以下面就是最终的HTML了页面基本不会变大量的工作是在JavaScript的编写上。 div idwrapperdiv idfileWrapper classfile_wrapperdiv idinfoHTML5 Audio API showcase | An Audio Viusalizer/divlabel foruploadedFileDragdrop or select a file to play:/labelinput typefile iduploadedFile/input/divdiv idvisualizer_wrappercanvas idcanvas width800 height350/canvas/div /div 再稍微写一点样式 #fileWrapper {transition: all 0.5s ease; } #fileWrapper: hover {opacity: 1!important; } #visualizer_wrapper {text-align: center; } 向Visualizer对象的原型中新加一个方法用于监听文件选择既前面讨论的onchange事件并在事件中获取选择的文件。 _addEventListner: function() {var that this,audioInput document.getElementById(uploadedFile),dropContainer document.getElementsByTagName(canvas)[0];//监听是否有文件被选中audioInput.onchange function() {//这里判断一下文件长度可以确定用户是否真的选择了文件如果点了取消则文件长度为0if (audioInput.files.length ! 0) {that.file audioInput.files[0]; //将文件赋值到Visualizer对象的属性上that.fileName that.file.name;that._start(); //获取到文件后开始程序这个方法会在后面定义并实现};}; } 上面代码中我们假设已经写好了一个进一步处理文件的方法_start()在获取到文件后赋值给Visualizer对象的file属性之后在_start()方法里我们就可以通过访问this.file来得到该文件了当然你也可以直接让_start()方法接收一个file参数但将文件赋值到Visualizer的属性上的好处之一是我们可以在对象的任何方法中都能获取该文件 不用想怎么用参数传来传去。同样将文件名赋值到Visualizer的fileName属性当中进行保存也是为了方便之后在音乐播放过程中显示当前播放的文件。 通过拖拽获取 我们把页面中的canvas作为放置文件的目标在它身上监听拖拽事件dragenter,dragover,drop等。 还是在上面已经添加好的_ addEventListner方法里接着写三个事件监听的代码。 dropContainer.addEventListener(dragenter, function() {that._updateInfo(Drop it on the page, true); }, false); dropContainer.addEventListener(dragover, function(e) {e.stopPropagation();e.preventDefault();e.dataTransfer.dropEffect copy; //设置文件放置类型为拷贝 }, false); dropContainer.addEventListener(dragleave, function() {that._updateInfo(that.info, false); }, false); dropContainer.addEventListener(drop, function(e) {e.stopPropagation();e.preventDefault();that.file e.dataTransfer.files[0]; //获取文件并赋值到Visualizer对象that.fileName that.file.name;that._start(); }, false); 注意到上面代码中我们在dragover时设置文件拖放模式为copy,既以复制的形式获取文件如果不进行设置无法正确获取文件 然后在drop事件里我们获得文件以进行一下步操作。 用FileReader读取文件为ArrayBuffer 下面来看这个_start()方法现在文件得到 了但首先需要将获取的文件转换为ArrayBuffer格式才能够传递给AudioContext进行解码所以接下来_start()方法中要干的事情就是实例化一个FileReader来将文件读取为ArrayBuffer格式。 _start: function() {//read and decode the file into audio array buffervar that this, //当前this指代Visualizer对象赋值给that以以便在其他地方使用file this.file, //从Visualizer对象上获取前面得到的文件fr new FileReader(); //实例化一个FileReader用于读取文件fr.onload function(e) { //文件读取完后调用此函数var fileResult e.target.result; //这是读取成功得到的结果ArrayBuffer数据var audioContext that.audioContext; //从Visualizer得到最开始实例化的AudioContext用来做解码ArrayBufferaudioContext.decodeAudioData(fileResult, function(buffer) { //解码成功则调用此函数参数buffer为解码后得到的结果that._visualize(audioContext, buffer); //调用_visualize进行下一步处理此方法在后面定义并实现}, function(e) { //这个是解码失败会调用的函数console.log(!哎玛文件解码失败:();});};//将上一步获取的文件传递给FileReader从而将其读取为ArrayBuffer格式fr.readAsArrayBuffer(file); } 注意这里我们把this赋值给了that然后再 audioContext.decodeAudioData的回调函数中使用that来指代我们的Visualizer对象。这是因为作用域的原因。我们知道JavaScript中无法通过花括号来创建代码块级作用域而唯一可以创建作用域的便是函数。一个函数就是一个作用域。函数内部的this指向的对象要视情况而定就上面的代码来说它是audioContext。所以如果想要在这个回调函数中调用Visualizer身上方法或属性则需要通过另一个变量来传递这里是that,我们通过将外层this指向的是我们的Viusalizer对象赋值给新建的局部变量that,此时that便可以传递到内层作用域中而不会与内层作用域里面原来的this相冲突。像这样的用法在源码的其他地方也有使用细心的你可以下载本文的源码慢慢研究。 所以在 audioContext.decodeAudioData的回调函数里当解码完成得到audiobuffer文件buffer参数后再把audioContext和buffer传递给Visualizer的_visualize()方法进一步处理播放音乐和绘制频谱图。当然此时_visualize()方法还没有下下面便开始实现它。 创建Analyser分析器及播放音频 上面已经将获取的文件进行解码得到了audio buffer数据。接下来是设置我们的AudioContext以及获取频谱能量信息的Analyser节点。向Visualizer对象添加_visualize方法我们在这个方法里完成这些工作。 播放音频 首先将buffer赋值给audioContext。AudioContext只相当于一个容器要让它真正丰富起来需要将实际的音乐信息传递给它的。也就是将audio buffer数据传递给它的BufferSource属性。 其实到了这里你应该有点晕了不过没关系看代码就会更明白一些程序员是理解代码优于文字的一种生物。 var audioBufferSouceNode audioContext.createBufferSource(); audioBufferSouceNode.buffer buffer; 就这么两名把音频文件的内容装进了AudioContext。 这时已经可以开始播放我们的音频了。 audioBufferSouceNode.start(0); 这里参数是时间表示从这段音频的哪个时刻开始播放。 注意在旧版本的浏览器里是使用onteOn()来进行播放的参数一样指开始时刻。 但此时是听不到声音的因为还差一步需要将audioBufferSouceNode连接到audioContext.destination这个AudioContext的destination也就相关于speaker扬声器。 audioBufferSouceNode.connect(audioContext.destination); audioBufferSouceNode.start(0); 此刻就能够听到扬声器传过来动听的声音了。 _visualize: function(audioContext, buffer) {var audioBufferSouceNode audioContext.createBufferSource();audioBufferSouceNode.connect(audioContext.destination);audioBufferSouceNode.buffer buffer;audioBufferSouceNode.start(0); } 创建分析器 创建获取频谱能量值的analyser节点。 var analyser audioContext.createAnalyser(); 上面一步我们是直接将audioBufferSouceNode与audioContext.destination相连的音频就直接输出到扬声器开始播放了现在为了将音频在播放前截取所以要把analyser插在audioBufferSouceNode与audioContext.destination之间。明白了这个道理代码也就很简单了audioBufferSouceNode连接到analyser,analyser连接destination。 audioBufferSouceNode.connect(analyser); analyser.connect(audioContext.destination); 然后再开始播放此刻所有音频数据都会经过analyser我们再从analyser中获取频谱的能量信息将其画出到Canvas即可。 假设我们已经写好了画频谱图的方法_drawSpectrum(analyser); _visualize: function(audioContext, buffer) {var audioBufferSouceNode audioContext.createBufferSource(),analyser audioContext.createAnalyser();//将source与分析器连接audioBufferSouceNode.connect(analyser);//将分析器与destination连接这样才能形成到达扬声器的通路analyser.connect(audioContext.destination);//将上一步解码得到的buffer数据赋值给sourceaudioBufferSouceNode.buffer buffer;//播放audioBufferSouceNode.start(0);//音乐响起后把analyser传递到另一个方法开始绘制频谱图了因为绘图需要的信息要从analyser里面获取this._drawSpectrum(analyser); } 绘制精美的频谱图 接下来的工作也是最后一步也就是实现_drawSpectrum()方法将跟随音乐而灵动的柱状频谱图画出到页面。 绘制柱状能量槽 首先你要对数字信号处理有一定了解吓人的不了解也没多大关系。频谱反应的是声音各频率上能量的分布所以叫能量槽也没有硬要跟游戏联系起来的嫌疑是将输入的信号经过傅里叶变化得到的大学里的知识终于还是可以派得上用场了。但特么我知道这些又怎样呢仅仅为了装逼显摆而以。真实的频谱图是频率上连续的不是我们看到的最终效果那样均匀分开锯齿状的。 通过下面的代码我们可以从analyser中得到此刻的音频中各频率的能量值。 var array new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(array); 此刻array中存储了从低频0Hz到高频~Hz的所有数据。频率做为X轴能量值做为Y轴我们可以得到类似下面的图形。 你也可以上传文件自己看一下效果 http://sandbox.runjs.cn/show/1kn8nr4l  所以比如array[0]100,我们就知道在x0处画一个高为100单位长度的长条array[1]50然后在x1画一个高为50单位长度的柱条从此类推如果用一个for循环遍历array将其全部画出的话便是你看到的上图。 采样 但我们要的不是那样的效果我们只需在所有数据中进行抽样比如设定一个步长100进度抽取来画出整个频谱图中的部分柱状条。 或者先根据画面的大小设计好每根柱条的宽度以及他们的间隔从而计算出画面中一共需要共多少根再来推算出这个采样步长该取多少本例便是这样实现的。说来还是有点晕下面看简单的代码 var canvas document.getElementById(canvas),meterWidth 10, //能量条的宽度gap 2, //能量条间的间距meterNum 800 / (10 2); //计算当前画布上能画多少条 var step Math.round(array.length / meterNum); //计算从analyser中的采样步长 我们的画布即Canvas宽800px,同时我们设定柱条宽10px , 柱与柱间间隔为2px所以得到meterNum为总共可以画的柱条数。再用数组总长度除以这个数目就得到采样的步长即在遍历array时每隔step这么长一段我们从数组中取一个值出来画这个值为array[i*step]。这样就均匀地取出meterNum个值从而正确地反应了原来频谱图的形状。 var canvas document.getElementById(canvas),cwidth canvas.width,cheight canvas.height - 2,meterWidth 10, //能量条的宽度gap 2, //能量条间的间距meterNum 800 / (10 2), //计算当前画布上能画多少条ctx canvas.getContext(2d),array new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(array); var step Math.round(array.length / meterNum);计算从 analyser中的采样步长 ctx.clearRect(0, 0, cwidth, cheight); //清理画布准备画画 //定义一个渐变样式用于画图 gradient ctx.createLinearGradient(0, 0, 0, 300); gradient.addColorStop(1, #0f0); gradient.addColorStop(0.5, #ff0); gradient.addColorStop(0, #f00); ctx.fillStyle gradient; //对信源数组进行抽样遍历画出每个频谱条 for (var i 0; i meterNum; i) {var value array[i * step];ctx.fillRect(i * 12 /*频谱条的宽度条间间距*/ , cheight - value capHeight, meterWidth, cheight); } 使用requestAnimationFrame让柱条动起来 但上面绘制的仅仅是某一刻的频谱要让整个画面动起来我们需要不断更新画面window.requestAnimationFrame()正好提供了更新画面得到动画效果的功能关于requestAnimationFrame的使用及更多信息可以从我的上一篇博文requestAnimationFrameWeb中写动画的另一种选择中了解这里直接给出简单改造后的代码即得到我们要的效果了跟随音乐而灵动的频谱柱状图。 var canvas document.getElementById(canvas),cwidth canvas.width,cheight canvas.height - 2,meterWidth 10, //能量条的宽度gap 2, //能量条间的间距meterNum 800 / (10 2), //计算当前画布上能画多少条ctx canvas.getContext(2d); //定义一个渐变样式用于画图 gradient ctx.createLinearGradient(0, 0, 0, 300); gradient.addColorStop(1, #0f0); gradient.addColorStop(0.5, #ff0); gradient.addColorStop(0, #f00); ctx.fillStyle gradient; var drawMeter function() {var array new Uint8Array(analyser.frequencyBinCount);analyser.getByteFrequencyData(array);var step Math.round(array.length / meterNum); //计算采样步长ctx.clearRect(0, 0, cwidth, cheight); //清理画布准备画画for (var i 0; i meterNum; i) {var value array[i * step];ctx.fillRect(i * 12 /*频谱条的宽度条间间距*/ , cheight - value capHeight, meterWidth, cheight);}requestAnimationFrame(drawMeter); } requestAnimationFrame(drawMeter); 查看效果 http://sandbox.runjs.cn/show/q1ng0jgp 绘制缓慢降落的帽头 到上面一步主要工作已经完成。最后为了美观再实现一下柱条上方缓慢降落的帽头。 原理也很简单就是在绘制柱条的同时在同一X轴的位置再绘制一个短的柱条并且其开始和结束位置都要比频谱中的柱条高。难的地方便是如何实现缓慢降落。 首先要搞清楚的一点是我们拿一根柱条来说明问题当此刻柱条高度高于前一时刻时我们看到的是往上冲的一根频谱所以这时帽头是紧贴着正文柱条的这个好画。考虑相反的情况当此刻高度要低于前一时刻的高度时下方柱条是立即缩下去的同时我们需要记住上一时刻帽头的高度位置此刻画的时候就按照前一时刻的位置将Y-1来画。如果下一时刻频谱柱条还是没有超过帽头的位置继续让它下降Y-1画出帽头。 通过上面的分析所以我们在每次画频谱的时刻需要将此刻频谱及帽头的Y值即垂直方向的位置记到一个循环外的变量中在下次绘制的时刻从这个变量中读取将此刻的值与变量中保存的上一刻的值进行比较然后按照上面的分析作图。 最后给出实现的代码 _drawSpectrum: function(analyser) {var canvas document.getElementById(canvas),cwidth canvas.width,cheight canvas.height - 2,meterWidth 10, //频谱条宽度gap 2, //频谱条间距capHeight 2,capStyle #fff,meterNum 800 / (10 2), //频谱条数量capYPositionArray []; //将上一画面各帽头的位置保存到这个数组ctx canvas.getContext(2d),gradient ctx.createLinearGradient(0, 0, 0, 300);gradient.addColorStop(1, #0f0);gradient.addColorStop(0.5, #ff0);gradient.addColorStop(0, #f00);var drawMeter function() {var array new Uint8Array(analyser.frequencyBinCount);analyser.getByteFrequencyData(array);var step Math.round(array.length / meterNum); //计算采样步长ctx.clearRect(0, 0, cwidth, cheight);for (var i 0; i meterNum; i) {var value array[i * step]; //获取当前能量值if (capYPositionArray.length Math.round(meterNum)) {capYPositionArray.push(value); //初始化保存帽头位置的数组将第一个画面的数据压入其中};ctx.fillStyle capStyle;//开始绘制帽头if (value capYPositionArray[i]) { //如果当前值小于之前值ctx.fillRect(i * 12, cheight - (--capYPositionArray[i]), meterWidth, capHeight); //则使用前一次保存的值来绘制帽头} else {ctx.fillRect(i * 12, cheight - value, meterWidth, capHeight); //否则使用当前值直接绘制capYPositionArray[i] value;};//开始绘制频谱条ctx.fillStyle gradient;ctx.fillRect(i * 12, cheight - value capHeight, meterWidth, cheight);}requestAnimationFrame(drawMeter);}requestAnimationFrame(drawMeter); } Reference: A question about how to make an audio visualizer: http://stackoverflow.com/questions/3351147/html5-audio-visualizerWeb audio API: http://www.html5rocks.com/en/tutorials/webaudio/intro/File reader in JavaScript: https://developer.mozilla.org/en-US/docs/Web/API/FileReaderLocal audio visualizer source code: http://cbrandolino.github.io/local-audio-visualizer/docs/local_audio_visualizerAudio context from MDN: https://developer.mozilla.org/en-US/docs/Web/API/AudioContextWindow.requestAnimationFrame():https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame3d visualizer with three.js : http://do.adive.in/music/A CodePen example: http://s.codepen.io/Wayou/fullpage/auCLE?Visualizer tutorial : http://www.smartjava.org/content/exploring-html5-web-audio-visualizing-soundWeb audio examples from Google code : http://chromium.googlecode.com/svn/trunk/samples/audio/index.html转自https://www.cnblogs.com/Wayou/p/3543577.html#top
http://www.pierceye.com/news/384452/

相关文章:

  • 免费做一建或二建题目的网站colorway wordpress
  • 简单网站建设合同贵州省高层建筑信息平台
  • 手机网站登录模板电视剧百度风云榜
  • 一嗨租车网站建设的功能特色梅林做网站
  • 网站关于我们怎么做36氪 wordpress 模板
  • 医疗网站建设计划书菏泽手机网站建设
  • 南京外贸网站建设哪家好免费网站建站方法
  • 文化馆建设网站网架公司有哪些
  • 企业如何申请网站51网站空间相册
  • 自己电脑做网站服务器系统网站建设违约交付
  • 什么叫域名访问网站wordpress app 接口
  • 学生网站建设实训总结工信部备案号查询平台
  • 凡科建站如何制作论坛备案网站需要多久
  • 网站建设的公司哪家是上市公司专业外贸网站制作
  • 建站公司杭州免费投票网站制作
  • 网站优化公司效果网络营销毕业后做什么工作
  • 移动互联网的应用论文可以优化网络的软件
  • 网站建设软件哪个最好郑州广告设计与制作公司
  • 浦口区网站建设售后保障如何维护网站
  • 企业网站建设 安全合肥做网站加盟
  • 水果网络营销策划方案电商网站怎样优化
  • 免费数据源网站wordpress主页面
  • 做网站百度收费吗青岛冠通市政建设有限公司网站
  • 菜鸟建网站福建福州罗源建设局网站
  • 企业内网网站制作自己的网站多少钱
  • 关于公司网站建设的申请wordpress站群功能
  • 外贸做企业什么网站珠海的网站建设
  • 做网站教程百度云外贸soho建站公司
  • 上海市网站建设网站增加导航栏
  • 电子政务网站模版网站制作排名优化