WebGL利用FBO完成立方體貼圖效果完整實例(附demo源碼下載)
本文實例講述了WebGL利用FBO完成立方體貼圖效果的方法。分享給大家供大家參考,具體如下:
這篇主要記錄WebGL的一些基本要點,順便也學(xué)習(xí)下如何使用FBO與環(huán)境貼圖。先看下效果圖(需要支持WebGL,Chrome,火狐,IE11)。

主要實現(xiàn)過程如下,先用FBO輸出當(dāng)前環(huán)境在立方體紋理中,再畫出當(dāng)前立方體,最后畫球,并且把FBO關(guān)聯(lián)的紋理貼在這個球面上。
開始WebGL時,最好有些OpenGL基礎(chǔ),在前面講Obj完善與MD2時,大家可能已經(jīng)發(fā)現(xiàn)了,因為著色器的添加使用,原來一些Opengl大部分API已經(jīng)沒有使用。WebGL就和這差不多,大部分功能是著色器完成主要功能,記錄下主要過程,大家可以比較下前面的,看看是不是很像,為了熟悉WebGL基本功能,本文沒有利用比較完善的框架,只是用到一個幫助計算矩陣的框架(gl-matrix.js).
和使用OpenGL一樣,我們要初始化使用環(huán)境,提取一些全局使用量。相關(guān)代碼如下:
初始化:
var gl;//WebGLRenderingContext
var cubeVBO;//Cube buffer ID
var sphereVBO;//球體VBO
var sphereEBO;//球體EBO
var cubeTexID;//立方體紋理ID
var fboBuffer;//楨緩存對象
var glCubeProgram;//立方體著色器應(yīng)用
var glSphereProgram;//球體著色器應(yīng)用
var fboWidth = 512;//楨緩存綁定紋理寬度
var fboHeight = 512;//楨緩存綁定紋理高度
var targets;//立方體貼圖六個方向
var pMatrix = mat4.create();//透視矩陣
var vMatrix = mat4.create();//視圖矩陣
var eyePos = vec3.fromValues(0.0, 1.0, 0.0);//眼睛位置
var eyeLookat = vec3.fromValues(0.0, -0.0, 0.0);//眼睛方向
var spherePos = vec3.fromValues(0.0, -0.0, 0.0);//球體位置
var canvanName;
function webGLStart(cName) {
canvanName = cName;
InitWebGL();
InitCubeShader();
InitSphereShader();
InitCubeBuffer();
InitSphereBuffer();
InitFBOCube();
//RenderFBO();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
tick();
}
function InitWebGL() {
//var canvas = document.getElementById(canvanName);
InitGL(canvanName);
}
function InitGL(canvas) {
try {
//WebGLRenderingContext
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
} catch (e) { }
if (!gl) { alert("你的瀏覽器不支持WebGL"); }
}
在這里,我們初始化在網(wǎng)頁中WebGL的上下方環(huán)境,并給出一系列初始化過程。下面先給出房間,也就是其中立方體的相關(guān)代碼。
立方體:
function InitCubeShader() {
//WebGLShader
var shader_vertex = GetShader("cubeshader-vs");
var shader_fragment = GetShader("cubeshader-fs");
//WebglCubeProgram
glCubeProgram = gl.createProgram();
gl.attachShader(glCubeProgram, shader_vertex);
gl.attachShader(glCubeProgram, shader_fragment);
gl.linkProgram(glCubeProgram);
if (!gl.getProgramParameter(glCubeProgram, gl.LINK_STATUS)) {
alert("Shader hava error.");
}
gl.useProgram(glCubeProgram);
glCubeProgram.positionAttribute = gl.getAttribLocation(glCubeProgram, "a_position");
glCubeProgram.normalAttribute = gl.getAttribLocation(glCubeProgram, "a_normal");
glCubeProgram.texCoordAttribute = gl.getAttribLocation(glCubeProgram, "a_texCoord");
glCubeProgram.view = gl.getUniformLocation(glCubeProgram, "view");
glCubeProgram.perspective = gl.getUniformLocation(glCubeProgram, "perspective");
}
function InitCubeBuffer() {
var cubeData = [
-10.0, -10.0, -10.0, 0.0, 0.0, -10.0, 1.0, 0.0,
-10.0, 10.0, -10.0, 0.0, 0.0, -10.0, 1.0, 1.0,
10.0, 10.0, -10.0, 0.0, 0.0, -10.0, 0.0, 1.0,
10.0, 10.0, -10.0, 0.0, 0.0, -10.0, 0.0, 1.0,
10.0, -10.0, -10.0, 0.0, 0.0, -10.0, 0.0, 0.0,
-10.0, -10.0, -10.0, 0.0, 0.0, -10.0, 1.0, 0.0,
-10.0, -10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0,
10.0, -10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 0.0,
10.0, 10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 1.0,
10.0, 10.0, 10.0, 0.0, 0.0, 10.0, 1.0, 1.0,
-10.0, 10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 1.0,
-10.0, -10.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0,
-10.0, -10.0, -10.0, 0.0, -10.0, 0.0, 0.0, 0.0,
10.0, -10.0, -10.0, 0.0, -10.0, 0.0, 1.0, 0.0,
10.0, -10.0, 10.0, 0.0, -10.0, 0.0, 1.0, 1.0,
10.0, -10.0, 10.0, 0.0, -10.0, 0.0, 1.0, 1.0,
-10.0, -10.0, 10.0, 0.0, -10.0, 0.0, 0.0, 1.0,
-10.0, -10.0, -10.0, 0.0, -10.0, 0.0, 0.0, 0.0,
10.0, -10.0, -10.0, 10.0, 0.0, 0.0, 0.0, 0.0,
10.0, 10.0, -10.0, 10.0, 0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 1.0, 1.0,
10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 1.0, 1.0,
10.0, -10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 1.0,
10.0, -10.0, -10.0, 10.0, 0.0, 0.0, 0.0, 0.0,
10.0, 10.0, -10.0, 0.0, 10.0, 0.0, 0.0, 0.0,
-10.0, 10.0, -10.0, 0.0, 10.0, 0.0, 1.0, 0.0,
-10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 1.0, 1.0,
-10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 1.0, 1.0,
10.0, 10.0, 10.0, 0.0, 10.0, 0.0, 0.0, 1.0,
10.0, 10.0, -10.0, 0.0, 10.0, 0.0, 0.0, 0.0,
-10.0, 10.0, -10.0, -10.0, 0.0, 0.0, 0.0, 0.0,
-10.0, -10.0, -10.0, -10.0, 0.0, 0.0, 1.0, 0.0,
-10.0, -10.0, 10.0, -10.0, 0.0, 0.0, 1.0, 1.0,
-10.0, -10.0, 10.0, -10.0, 0.0, 0.0, 1.0, 1.0,
-10.0, 10.0, 10.0, -10.0, 0.0, 0.0, 0.0, 1.0,
-10.0, 10.0, -10.0, -10.0, 0.0, 0.0, 0.0, 0.0,
];
cubeVBO = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVBO);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeData), gl.STATIC_DRAW);
}
function RenderCube() {
gl.useProgram(glCubeProgram);
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVBO);
gl.vertexAttribPointer(glCubeProgram.positionAttribute, 3, gl.FLOAT, false, 32, 0);
gl.enableVertexAttribArray(glCubeProgram.positionAttribute);
gl.vertexAttribPointer(glCubeProgram.normalAttribute, 3, gl.FLOAT, false, 32, 12);
gl.enableVertexAttribArray(glCubeProgram.normalAttribute);
gl.vertexAttribPointer(glCubeProgram.texCoordAttribute, 2, gl.FLOAT, false, 32, 24);
gl.enableVertexAttribArray(glCubeProgram.texCoordAttribute);
gl.uniformMatrix4fv(glCubeProgram.view, false, vMatrix);
gl.uniformMatrix4fv(glCubeProgram.perspective, false, pMatrix);
gl.drawArrays(gl.TRIANGLES, 0, 36);
}
上面的代碼主要分為初始化立方體的著色器對象,初始化相關(guān)緩存,然后繪制立方體,可以說在Opengl中,如果用著色器來畫,過程也是差不多的,在Opengl里,已經(jīng)沒有固定管線的一些功能如InterleavedArrays來指定是頂點還是法線或是紋理了,統(tǒng)一用vertexAttribPointer來傳遞應(yīng)用程序與著色器之間的數(shù)據(jù)。在前面 MD2楨動畫實現(xiàn)里面后面的參數(shù)傳遞改進(jìn)版也有相關(guān)應(yīng)用。
相應(yīng)著立方體著色器主要代碼如下:
立方體著色器實現(xiàn):
<script id="cubeshader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 normal;
varying vec3 tex1;
varying vec3 tex2;
void main( void )
{
float x = tex1.x * 6.28 * 8.0; //2兀 * 8
float y = tex1.y * 6.28 * 8.0; //2兀 * 8
//cos(x)= 8個 (1 -1 1)
gl_FragColor = vec4(tex2,1.0) * vec4(sign(cos(x)+cos(y))); //
//gl_FragColor = vec4(normal*vec3(0.5)+vec3(0.5), 1);
}
</script>
<script id="cubeshader-vs" type="x-shader/x-vertex">
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord;
uniform mat4 view;
uniform mat4 perspective;
varying vec3 normal;
varying vec3 tex1;
varying vec3 tex2;
void main( void )
{
gl_Position = perspective * view * vec4(a_position,1.0);
normal = a_normal;
tex1 = vec3(a_texCoord,0.0);
tex2 = normalize(a_position)*0.5+0.5;
}
</script>
著色器中,已經(jīng)沒有ftransform()功能可供調(diào)用,要自己傳遞如模型,視圖,透視矩陣,在這里,模型是以原點為中心來繪畫,意思模型視圖矩陣也就是視圖矩陣,所以屏幕位置的計算只需要視圖和透視矩陣。在片斷著色器中,x,y是從頂點著色器中的紋理坐標(biāo)傳遞過來,相應(yīng)過程6.28*8.0,相當(dāng)于8個360度,用于控制立方體上的方塊顯示,而tex2是著色器中的頂點映射[0,1]的值,分別給立方體的六面分別設(shè)置不同的意思,然后用二個矢量的乘積來混合這二種顏色顯示,gl_FragColor = vec4(tex2,1.0) * vec4(sign(cos(x)+cos(y)))。
在顯示球體之前,應(yīng)該先生成當(dāng)前環(huán)境的立方體繪圖,在這里使用FBO,先生成楨緩存和立方體繪理,并關(guān)聯(lián),然后以原點為中心,分別向上下左右前右繪圖,然后利用楨緩沖分別輸出到立方體上的六個面,主要代碼如下:
FBO與立方體紋理:
function InitFBOCube() {
// WebGLFramebuffer
fboBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fboBuffer);
fboBuffer.width = 512;
fboBuffer.height = 512;
cubeTexID = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTexID);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
for (var i = 0; i < targets.length; i++) {
gl.texImage2D(targets[i], 0, gl.RGBA, fboBuffer.width, fboBuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
function RenderFBO() {
gl.disable(gl.DEPTH_TEST);
gl.viewport(0, 0, fboBuffer.width, fboBuffer.height);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.bindFramebuffer(gl.FRAMEBUFFER, fboBuffer);
for (var i = 0; i < targets.length; i++) {
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, targets[i], cubeTexID, null);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
mat4.perspective(pMatrix, 45, fboBuffer.width / fboBuffer.height, 0.1, 100.0);
for (var i = 0; i < targets.length; i++) {
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, targets[i], cubeTexID, null);
var lookat = vec3.create();
var up = vec3.create();
up[1] = 1.0;
if (i == 0) {
lookat[0] = -1.0;
} else if (i == 1) {
lookat[0] = 1.0;
} else if (i == 2) {
lookat[1] = -1.0;
up[0] = 1.0;
} else if (i == 3) {
lookat[1] = 1.0;
up[0] = 1.0;
} else if (i == 4) {
lookat[2] == -1.0;
} else if (i == 5) {
lookat[2] = 1.0;
} else {
}
//vec3.fromValues(0.0, 0.0, 0.0)
vMatrix = mat4.create();
mat4.lookAt(vMatrix, vec3.fromValues(0.0, 0.0, 0.0), lookat, up);
//mat4.scale(vMatrix, vMatrix, vec3.fromValues(-1.0, -1.0, -1.0));
//mat4.translate(vMatrix, vMatrix, spherePos);
RenderCube();
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.enable(gl.DEPTH_TEST);
}
在上面不知是gl-matrix提供的矩陣算法有問題,還是本來應(yīng)該這樣,在上下面的時候生成的紋理圖不對,需要偏轉(zhuǎn)攝像機(jī)的向上矢量。因為這是攝像機(jī)位置與目標(biāo)的生成的Z軸和設(shè)定的UP軸平行了,這樣導(dǎo)致不能正確計算X軸,然后對應(yīng)的UP軸也計算不出來,相應(yīng)視圖矩陣出現(xiàn)錯誤。
最后是球體的繪畫,代碼主要和立方體的差不多,注意球體的頂點算法。
球體:
function InitSphereShader() {
//WebGLShader
var shader_vertex = GetShader("sphereshader-vs");
var shader_fragment = GetShader("sphereshader-fs");
//WebglCubeProgram
glSphereProgram = gl.createProgram();
gl.attachShader(glSphereProgram, shader_vertex);
gl.attachShader(glSphereProgram, shader_fragment);
gl.linkProgram(glSphereProgram);
if (!gl.getProgramParameter(glSphereProgram, gl.LINK_STATUS)) {
alert("Shader hava error.");
}
glSphereProgram.positionAttribute = gl.getAttribLocation(glSphereProgram, "a_position");
glSphereProgram.normalAttribute = gl.getAttribLocation(glSphereProgram, "a_normal");
glSphereProgram.eye = gl.getUniformLocation(glSphereProgram, "eye");
glSphereProgram.mapCube = gl.getUniformLocation(glSphereProgram, "mapCube");
glSphereProgram.model = gl.getUniformLocation(glSphereProgram, "model");
glSphereProgram.view = gl.getUniformLocation(glSphereProgram, "view");
glSphereProgram.perspective = gl.getUniformLocation(glSphereProgram, "perspective");
}
function InitSphereBuffer() {
var radius = 1;
var segments = 16;
var rings = 16;
var length = segments * rings * 6;
var sphereData = new Array();
var sphereIndex = new Array();
for (var y = 0; y < rings; y++) {
var phi = (y / (rings - 1)) * Math.PI;
for (var x = 0; x < segments; x++) {
var theta = (x / (segments - 1)) * 2 * Math.PI;
sphereData.push(radius * Math.sin(phi) * Math.cos(theta));
sphereData.push(radius * Math.cos(phi));
sphereData.push(radius * Math.sin(phi) * Math.sin(theta));
sphereData.push(Math.sin(phi) * Math.cos(theta));
sphereData.push(radius * Math.cos(phi))
sphereData.push(Math.sin(phi) * Math.sin(theta));
}
}
for (var y = 0; y < rings - 1; y++) {
for (var x = 0; x < segments - 1; x++) {
sphereIndex.push((y + 0) * segments + x);
sphereIndex.push((y + 1) * segments + x);
sphereIndex.push((y + 1) * segments + x + 1);
sphereIndex.push((y + 1) * segments + x + 1);
sphereIndex.push((y + 0) * segments + x + 1)
sphereIndex.push((y + 0) * segments + x);
}
}
sphereVBO = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVBO);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(sphereData), gl.STATIC_DRAW);
sphereVBO.numItems = segments * rings;
sphereEBO = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereEBO);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(sphereIndex), gl.STATIC_DRAW);
sphereEBO.numItems = sphereIndex.length;
}
function RenderSphere() {
gl.useProgram(glSphereProgram);
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVBO);
gl.vertexAttribPointer(glSphereProgram.positionAttribute, 3, gl.FLOAT, false, 24, 0);
gl.enableVertexAttribArray(glSphereProgram.positionAttribute);
gl.vertexAttribPointer(glSphereProgram.normalAttribute, 3, gl.FLOAT, false, 24, 12);
gl.enableVertexAttribArray(glSphereProgram.normalAttribute);
var mMatrix = mat4.create();
mat4.translate(mMatrix, mMatrix, spherePos);
gl.uniform3f(glSphereProgram.eye, eyePos[0],eyePos[1],eyePos[2]);
gl.uniformMatrix4fv(glSphereProgram.model, false, mMatrix);
gl.uniformMatrix4fv(glSphereProgram.view, false, vMatrix);
gl.uniformMatrix4fv(glSphereProgram.perspective, false, pMatrix);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTexID);
//gl.uniformMatrix4fv(glSphereProgram.mapCube, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereEBO);
gl.drawElements(gl.TRIANGLES, sphereEBO.numItems, gl.UNSIGNED_SHORT, 0);
gl.bindTexture(gl.TEXTURE_2D, null);
}
可以看到,也是和立方體一樣的三步,初始化著色器,初始化頂點與法線,繪畫。下面給出著色器代碼:
球體著色器:
<script id="sphereshader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 normal;
varying vec3 eyevec;
uniform samplerCube mapCube;
void main( void )
{
gl_FragColor = textureCube(mapCube, reflect(normalize(-eyevec), normalize(normal)));
}
</script>
<script id="sphereshader-vs" type="x-shader/x-vertex">
attribute vec3 a_position;
attribute vec3 a_normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 perspective;
uniform vec3 eye;
varying vec3 normal;
varying vec3 eyevec;
void main( void )
{
gl_Position = perspective * view * model * vec4(a_position,1.0);
eyevec = -eye;// a_position.xyz;
normal = a_normal;
}
</script>
和前面立方體有點不同的是,球體有自己的模型矩陣,這也是一般正常的用法,然后傳遞眼睛對應(yīng)球體頂點矢量與法線傳遞在片斷著色器中,在片斷著色器中,就有用到前面所生成的立方體紋理,我們根據(jù)眼睛經(jīng)過頂點通過對應(yīng)法向量反射到立體體紋理上的點來獲取當(dāng)前球體所對應(yīng)的環(huán)境顏色,在這里,我們可以直接調(diào)用textureCube來完成上面所說的過程,不需要我們手動來計算。
其中GetShader函數(shù)的使用,參照了http://msdn.microsoft.com/zh-TW/library/ie/dn302360(v=vs.85) 這里的講解。
可以說,上面主要的繪制函數(shù)已經(jīng)完成,但是我們這個是能動的,所以需要模擬如客戶端環(huán)境每隔多久繪制一次,主要代碼如下:
動畫:
function tick() {
Update();
OnDraw();
setTimeout(function () { tick() }, 15);
}
function OnDraw() {
//fbo rander CUBE_MAP
RenderFBO();
//element rander
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 200.0);
mat4.lookAt(vMatrix, eyePos, eyeLookat, vec3.fromValues(0.0, 1.0, 0.0));
RenderCube();
RenderSphere();
}
var lastTime = new Date().getTime();
function Update() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
//3000控制人眼的旋轉(zhuǎn)速度。8控制人眼的遠(yuǎn)近
eyePos[0] = Math.cos(elapsed / 3000) * 8;
eyePos[2] = Math.sin(elapsed / 2000) * 8;
spherePos[0] = Math.cos(elapsed / 4000) * 3;
spherePos[2] = Math.cos(elapsed / 4000) * 3;
}
}
在上面,每隔15毫秒調(diào)用一次Update與Draw函數(shù),其中Update用于更新眼睛與球體位置,Draw繪畫。
完整實例代碼點擊此處本站下載。
更多關(guān)于JS特效相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《jQuery動畫與特效用法總結(jié)》及《jQuery常見經(jīng)典特效匯總》
希望本文所述對大家JavaScript程序設(shè)計有所幫助。
相關(guān)文章
bootstrap實現(xiàn)的自適應(yīng)頁面簡單應(yīng)用示例
這篇文章主要介紹了bootstrap實現(xiàn)的自適應(yīng)頁面簡單應(yīng)用,結(jié)合具體實例形式分析了基于bootstrap的列表布局結(jié)構(gòu)頁面實現(xiàn)與使用技巧,需要的朋友可以參考下2017-03-03
JavaScript將字符串轉(zhuǎn)換成字符編碼列表的方法
這篇文章主要介紹了JavaScript將字符串轉(zhuǎn)換成字符編碼列表的方法,實例分析了javascript中charCodeAt函數(shù)的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03
微信小程序scroll-view的滾動條設(shè)置實現(xiàn)
這篇文章主要介紹了微信小程序scroll-view的滾動條設(shè)置實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
調(diào)試Javascript代碼(瀏覽器F12及VS中debugger關(guān)鍵字)
目前,常用的瀏覽器IE、Chrome、Firefox都有相應(yīng)的腳本調(diào)試功能下面我就介紹如何在瀏覽器/VS中調(diào)試我們的JS代碼,感興趣的你可不要走開啊,希望本文對你有所幫助2013-01-01
深入理解ES6之?dāng)?shù)據(jù)解構(gòu)的用法
本文介紹了深入理解ES6之?dāng)?shù)據(jù)解構(gòu)的用法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01

