国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

有趣且重要的JS知識(shí)合集(18)瀏覽器實(shí)現(xiàn)前端錄音功能

這篇具有很好參考價(jià)值的文章主要介紹了有趣且重要的JS知識(shí)合集(18)瀏覽器實(shí)現(xiàn)前端錄音功能。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1、主題描述

兼容多個(gè)瀏覽器下的前端錄音功能,實(shí)現(xiàn)六大錄音功能:

1、開(kāi)始錄音

2、暫停錄音

3、繼續(xù)錄音

4、結(jié)束錄音

5、播放錄音

6、上傳錄音

2、示例功能

初始狀態(tài):

js 錄音,js有趣知識(shí),前端,javascript

開(kāi)始錄音:

js 錄音,js有趣知識(shí),前端,javascript

結(jié)束錄音:

js 錄音,js有趣知識(shí),前端,javascript

錄音流程 :

示例中的三個(gè)按鈕其實(shí)包含了六個(gè)上述功能,點(diǎn)擊開(kāi)始時(shí)開(kāi)始錄音,可以暫停/結(jié)束錄音,此操作后就可以播放播音/上傳錄音了噢~以下是對(duì)應(yīng)六大錄音功能示例代碼,那大家會(huì)發(fā)現(xiàn)HZRecorder是啥呢? 其實(shí)?HZRecorder 是錄音類,我們調(diào)用的都是該類里面的方法。

那大家肯定好奇,錄音是通過(guò)怎樣一種形式存在呢?其實(shí)用的就是瀏覽器的AudioContext對(duì)象,他旨在創(chuàng)建一個(gè)音頻dom,有輸入和輸出。具體想了解這對(duì)象的,可以去mdn看看

AudioContext

    /**
     * 錄音前準(zhǔn)備 檢查錄音設(shè)備是否到位
     */
    this.readyRecording = async function() {
      let recorder // 表示錄音類實(shí)例
      // 流模式下ready鉤子 res 為錄音類實(shí)例 或者 false
      await HZRecorder.ready().then(res => {
        recorder = res
      })
      return recorder
    }
    /**
     * 開(kāi)始錄音
     */
    this.startRecording = function() {
      recorder.start();
    }
    /**
     * 結(jié)束錄音
     */
    this.stopRecording = function() {
      recorder.end();
    }
    /**
     * 播放錄音
     */
    this.playRecording = function() {
      recorder.play(audio);
    }
    /**
     * 繼續(xù)錄音
     */
    this.resumeRecord = function() {
      recorder.again();
    }
    /**
     * 暫停錄音
     */
    this.pauseRecord = function() {
      recorder.stop();
    }
    /**
     * 重新錄音
     */
    this.reRecord = function() {
      this.startRecording()
    }
    /**
     * 上傳錄音
     */
    this.uploadRecord = function() {
      // 流模式下上傳
      recorder.upload(url, succ, fail)
    }

3、流模式下的錄音類

大家看到這標(biāo)題就好奇,啥叫流模式下的錄音類呢?那還有其他模式嗎?的確,我總結(jié)了下,是根據(jù)上傳錄音時(shí)的數(shù)據(jù)來(lái)區(qū)分的~我們常規(guī)情況下,上傳錄音都是流模式,也就是Content-Type為application/octem-stream,源碼如下

/**
 * 錄音類(針對(duì)content-type為application/octem-stream 的使用)
 * @param {*} stream 
 * @param {*} config 
 */
const HZRecorder = function (stream, config) {
  config = config || {};
  config.sampleBits = config.sampleBits || 8;      //采樣數(shù)位 8, 16  
  config.sampleRate = config.sampleRate || (44100 / 6);   //采樣率(1/6 44100)  


  //創(chuàng)建一個(gè)音頻環(huán)境對(duì)象  
  audioContext = window.AudioContext || window.webkitAudioContext;
  var context = new audioContext();

  //將聲音輸入這個(gè)對(duì)像  
  var audioInput = context.createMediaStreamSource(stream);

  //設(shè)置音量節(jié)點(diǎn)  
  var volume = context.createGain();
  audioInput.connect(volume);

  //創(chuàng)建緩存,用來(lái)緩存聲音  
  var bufferSize = 4096;

  // 創(chuàng)建聲音的緩存節(jié)點(diǎn),createScriptProcessor方法的  
  // 第二個(gè)和第三個(gè)參數(shù)指的是輸入和輸出都是雙聲道。  
  var recorder = context.createScriptProcessor(bufferSize, 2, 2);

  var audioData = {
    size: 0          //錄音文件長(zhǎng)度  
    , buffer: []     //錄音緩存  
    , inputSampleRate: context.sampleRate    //輸入采樣率  
    , inputSampleBits: 16       //輸入采樣數(shù)位 8, 16  
    , outputSampleRate: config.sampleRate    //輸出采樣率  
    , oututSampleBits: config.sampleBits       //輸出采樣數(shù)位 8, 16  
    , input: function (data) {
      this.buffer.push(new Float32Array(data));
      this.size += data.length;
    }
    , compress: function () { //合并壓縮  
      //合并  
      var data = new Float32Array(this.size);
      var offset = 0;
      for (var i = 0; i < this.buffer.length; i++) {
        data.set(this.buffer[i], offset);
        offset += this.buffer[i].length;
      }
      //壓縮  
      var compression = parseInt(this.inputSampleRate / this.outputSampleRate);
      var length = data.length / compression;
      var result = new Float32Array(length);
      var index = 0, j = 0;
      while (index < length) {
        result[index] = data[j];
        j += compression;
        index++;
      }
      return result;
    }
    , encodeWAV: function () {
      var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
      var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);
      var bytes = this.compress();
      var dataLength = bytes.length * (sampleBits / 8);
      var buffer = new ArrayBuffer(44 + dataLength);
      var data = new DataView(buffer);

      var channelCount = 1;//單聲道  
      var offset = 0;

      var writeString = function (str) {
        for (var i = 0; i < str.length; i++) {
          data.setUint8(offset + i, str.charCodeAt(i));
        }
      };

      // 資源交換文件標(biāo)識(shí)符   
      writeString('RIFF'); offset += 4;
      // 下個(gè)地址開(kāi)始到文件尾總字節(jié)數(shù),即文件大小-8   
      data.setUint32(offset, 36 + dataLength, true); offset += 4;
      // WAV文件標(biāo)志  
      writeString('WAVE'); offset += 4;
      // 波形格式標(biāo)志   
      writeString('fmt '); offset += 4;
      // 過(guò)濾字節(jié),一般為 0x10 = 16   
      data.setUint32(offset, 16, true); offset += 4;
      // 格式類別 (PCM形式采樣數(shù)據(jù))   
      data.setUint16(offset, 1, true); offset += 2;
      // 通道數(shù)   
      data.setUint16(offset, channelCount, true); offset += 2;
      // 采樣率,每秒樣本數(shù),表示每個(gè)通道的播放速度   
      data.setUint32(offset, sampleRate, true); offset += 4;
      // 波形數(shù)據(jù)傳輸率 (每秒平均字節(jié)數(shù)) 單聲道×每秒數(shù)據(jù)位數(shù)×每樣本數(shù)據(jù)位/8   
      data.setUint32(offset, channelCount * sampleRate * (sampleBits / 8), true); offset += 4;
      // 快數(shù)據(jù)調(diào)整數(shù) 采樣一次占用字節(jié)數(shù) 單聲道×每樣本的數(shù)據(jù)位數(shù)/8   
      data.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
      // 每樣本數(shù)據(jù)位數(shù)   
      data.setUint16(offset, sampleBits, true); offset += 2;
      // 數(shù)據(jù)標(biāo)識(shí)符   
      writeString('data'); offset += 4;
      // 采樣數(shù)據(jù)總數(shù),即數(shù)據(jù)總大小-44   
      data.setUint32(offset, dataLength, true); offset += 4;
      // 寫(xiě)入采樣數(shù)據(jù)   
      if (sampleBits === 8) {
        for (var i = 0; i < bytes.length; i++, offset++) {
          var s = Math.max(-1, Math.min(1, bytes[i]));
          var val = s < 0 ? s * 0x8000 : s * 0x7FFF;
          val = parseInt(255 / (65535 / (val + 32768)));
          data.setInt8(offset, val, true);
        }
      } else {
        for (var i = 0; i < bytes.length; i++, offset += 2) {
          var s = Math.max(-1, Math.min(1, bytes[i]));
          data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
        }
      }

      return new Blob([data], { type: 'audio/wav' });
    }
  };
  //開(kāi)始錄音  
  this.start = function () {
    audioInput.connect(recorder);
    recorder.connect(context.destination);
  };

  //停止  
  this.stop = function () {
    recorder.disconnect();
  };

  // 結(jié)束
  this.end = function () {
    context.close();
  };

  // 繼續(xù)
  this.again = function () {
    recorder.connect(context.destination);
  };

  //獲取音頻文件  
  this.getBlob = function () {
    this.stop();
    return audioData.encodeWAV();
  };

  //回放  
  this.play = function (audio) {
    audio.src = window.URL.createObjectURL(this.getBlob());
  };

  //上傳  
  this.upload = function (url, succ, fail) {
    const xhr = new XMLHttpRequest();
    xhr.overrideMimeType("application/octet-stream")
    // xhr.upload.addEventListener('progress', function (e) {
    // }, false);
    xhr.addEventListener('load', function (e) {
      succ(xhr.response)
    }, false);
    xhr.addEventListener('error', function (e) {
      fail(xhr.response);
    }, false);
    xhr.addEventListener('abort', function (e) {
      fail(xhr.response);
    }, false);
    xhr.open('POST', url);
    if(xhr.sendAsBinary){
      xhr.sendAsBinary(this.getBlob());
    }else{
      xhr.send(this.getBlob());
    }
  };

  //音頻采集  
  recorder.onaudioprocess = function (e) {
    audioData.input(e.inputBuffer.getChannelData(0));
  };
}

/**
 * 多瀏覽器兼容
 * @param {*} videoConfig 參數(shù)配置
 * @param {*} succ 成功回調(diào)
 * @param {*} fail 失敗回調(diào)
 * @returns promise
 */
HZRecorder.compatibleMedia = async function(videoConfig) {
	let streamPromise // 視頻promise
	if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia){
		// 最新標(biāo)準(zhǔn)API
		streamPromise = await navigator.mediaDevices.getUserMedia(videoConfig)
	} else if (navigator.webkitGetUserMedia){
		// webkit內(nèi)核瀏覽器
		streamPromise = await navigator.webkitGetUserMedia(videoConfig)
	} else if (navigator.mozGetUserMedia){
		// Firefox瀏覽器
		streamPromise = await navagator.mozGetUserMedia(videoConfig)
	} else if (navigator.getUserMedia){
		// 舊版API
		streamPromise = await navigator.getUserMedia(videoConfig)
	}
	return streamPromise
}
/**
 * 是否支持錄音
 * @returns 支持直接返回錄音類實(shí)例 : 返回false
 */
HZRecorder.ready = async function() {
	let instance // 錄音類實(shí)例(ready ok) | false (ready no)
	await HZRecorder.compatibleMedia({ audio: true }).then(stream => {
		instance = new HZRecorder(stream);
	}).catch(() => {
		instance = false
	})
	return instance
}

4、表單模式下的錄音類

和上述流模式的錄音類有區(qū)別的是,表單模式下適用于上傳錄音時(shí)Content-Type為application/x-www-form-urlencoded噢~

// --------------------------------------------------
	/**
	 * 錄音類(指定content-type為application/x-www-form-urlencoded使用)
	 * @param {*} stream 流對(duì)象
	 */
  const HZRecorderForm = function (stream) {

    //創(chuàng)建一個(gè)音頻環(huán)境對(duì)象  
    audioContext = window.AudioContext || window.webkitAudioContext;
    var ac = new audioContext();
    var chunks = [];
    var mediaRecorder
    var blobResult
    //開(kāi)始錄音  
    this.start = function () {
      if (!mediaRecorder) {
        var origin = ac.createMediaStreamSource(stream)
        var dest = ac.createMediaStreamDestination();
        mediaRecorder = new MediaRecorder(dest.stream);
        mediaRecorder.ondataavailable = function(e) {
          chunks.push(e.data);
        }
        mediaRecorder.onstop = function(evt) {
          blobResult = new Blob(chunks, { 'type' : 'audio/mpeg' });
  
        };
        origin.connect(dest);
      }
      mediaRecorder.start();
    };
    // 結(jié)束錄音
    this.end = function () {
      // 當(dāng)錄音類處于不活躍狀態(tài)時(shí),停止操作
      if (mediaRecorder.state === 'inactive') return
      mediaRecorder.requestData()
      mediaRecorder.stop();
    };
    // 暫停錄音
    this.stop = function() {
      // 當(dāng)錄音類處于不活躍狀態(tài)時(shí),停止操作
      if (mediaRecorder.state === 'inactive') return
      mediaRecorder.pause()
    }
    // 恢復(fù)錄音
    this.again = function() {
      // 當(dāng)錄音類處于不活躍狀態(tài)時(shí),停止操作
      if (mediaRecorder.state === 'inactive') return
      mediaRecorder.resume()
    }
    //上傳  
    this.upload = function (url, succ, err) {
      setTimeout(() => {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', url);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
        xhr.send(blobResult);
        xhr.onload = e => {
          // 請(qǐng)求完成 && 外部狀態(tài)碼200 && 內(nèi)部狀態(tài)碼1(這個(gè)內(nèi)部狀態(tài)碼自定義)
          if (xhr.readyState === 4 && xhr.status === 200 && JSON.parse(xhr.response).status === 1) {
            succ && succ(xhr.response)
          } else {
            err && err(JSON.parse(xhr.response).message)
          }
        }
      })
    };
  }
  
/**
 * 多瀏覽器兼容
 * @param {*} videoConfig 參數(shù)配置
 * @param {*} succ 成功回調(diào)
 * @param {*} fail 失敗回調(diào)
 * @returns promise
 */
HZRecorderForm.compatibleMedia = async function(videoConfig) {
	let streamPromise // 視頻promise
	if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia){
		// 最新標(biāo)準(zhǔn)API
		streamPromise = await navigator.mediaDevices.getUserMedia(videoConfig)
	} else if (navigator.webkitGetUserMedia){
		// webkit內(nèi)核瀏覽器
		streamPromise = await navigator.webkitGetUserMedia(videoConfig)
	} else if (navigator.mozGetUserMedia){
		// Firefox瀏覽器
		streamPromise = await navagator.mozGetUserMedia(videoConfig)
	} else if (navigator.getUserMedia){
		// 舊版API
		streamPromise = await navigator.getUserMedia(videoConfig)
	}
	return streamPromise
}
/**
 * 是否支持錄音
 * @returns 支持直接返回錄音類實(shí)例 : 返回false
 */
HZRecorderForm.ready = async function() {
	let instance // 錄音類實(shí)例(ready ok) | false (ready no)
	await HZRecorderForm.compatibleMedia({ audio: true }).then(stream => {
		instance = new HZRecorderForm(stream);
	}).catch(() => {
		instance = false
	})
	return instance
}

5、疑難解答

1、在錄音開(kāi)始前都必須調(diào)用readyRecording方法嗎?

必須噢,你也可以自己實(shí)現(xiàn)這功能,HZRecorder.ready()方法返回的是promise對(duì)象,其值在當(dāng)前有麥克風(fēng)時(shí)候,返回的是錄音類實(shí)例,你拿到此值就可以調(diào)用錄音類的方法,無(wú)麥克風(fēng)時(shí)候,返回的是false,表示當(dāng)前不具備錄音環(huán)境~

/**
     * 錄音前準(zhǔn)備 檢查錄音設(shè)備是否到位
     */
    this.readyRecording = async function() {
      let recorder // 表示錄音類實(shí)例
      // 流模式下ready鉤子 res 為錄音類實(shí)例 或者 false
      await HZRecorder.ready().then(res => {
        recorder = res
      })
      // 表單模式下ready鉤子 res 為錄音類實(shí)例 或者 false
      await HZRecorderForm.ready().then(res => {
        recorder = res
      })
      return recorder
    }

2、火狐瀏覽器提示?navigator.mediaDevices is undefined,找不到?

是的噢,火狐瀏覽器的navigator對(duì)象沒(méi)有mediaDevices這個(gè)屬性,所以這也是我為啥在錄音類里要加入compatibleMedia方法,此方法就是用來(lái)兼容各個(gè)瀏覽器的噢~火狐就是用的navigator.mozGetUserMedia方法

/**
 * 多瀏覽器兼容
 * @param {*} videoConfig 參數(shù)配置
 * @param {*} succ 成功回調(diào)
 * @param {*} fail 失敗回調(diào)
 * @returns promise
 */
HZRecorder.compatibleMedia = async function(videoConfig) {
	let streamPromise // 視頻promise
	if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia){
		// 最新標(biāo)準(zhǔn)API
		streamPromise = await navigator.mediaDevices.getUserMedia(videoConfig)
	} else if (navigator.webkitGetUserMedia){
		// webkit內(nèi)核瀏覽器
		streamPromise = await navigator.webkitGetUserMedia(videoConfig)
	} else if (navigator.mozGetUserMedia){
		// Firefox瀏覽器
		streamPromise = await navagator.mozGetUserMedia(videoConfig)
	} else if (navigator.getUserMedia){
		// 舊版API
		streamPromise = await navigator.getUserMedia(videoConfig)
	}
	return streamPromise
}

3、錄音類的ready方法,為啥要使用async/await呢?

這個(gè)就有點(diǎn)涉及異步的知識(shí)了,在一個(gè)異步函數(shù)里,return是屬于同步邏輯噢,promise.then屬于異步,所以 return 會(huì)先于 .then執(zhí)行的噢,這就和我們的想法不一致了,所以要await 阻塞代碼,拿到instance值了,再返回

/**
 * 是否支持錄音
 * @returns 支持直接返回錄音類實(shí)例 : 返回false
 */
HZRecorder.ready = async function() {
	let instance // 錄音類實(shí)例(ready ok) | false (ready no)
	await HZRecorder.compatibleMedia({ audio: true }).then(stream => {
		instance = new HZRecorder(stream);
	}).catch(() => {
		instance = false
	})
	return instance
}

4、錄音類為啥要使用?XMLHttpRequest 來(lái)觸發(fā)接口呢?

不一定要使用原生xhr噢,你也可以根據(jù)你需求來(lái)修改成axios/fetch/ajax等~這個(gè)不影響整體代碼的使用

5、流模式和表單模式的錄音類本質(zhì)上有啥區(qū)別?

其實(shí)在外層是上傳接口的請(qǐng)求頭區(qū)別,但在實(shí)際上,只是由于流模式下的寫(xiě)法,無(wú)法將音頻轉(zhuǎn)成mp3格式(默認(rèn)為wav格式),當(dāng)然網(wǎng)上也有小伙伴認(rèn)為引入lame庫(kù)來(lái)實(shí)現(xiàn)wav轉(zhuǎn)換mp3的操作,當(dāng)然可以啦~這不影響,只是對(duì)我來(lái)說(shuō),我是能不引入第三方庫(kù)就不引入。

而表單模式實(shí)際上用的瀏覽器支持的另一個(gè)接口?MediaRecorder

而MediaRecorder是專門(mén)來(lái)做錄制的,他想轉(zhuǎn)換格式的話,就簡(jiǎn)單的多,在錄制完觸發(fā)onstop時(shí),將可以將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成任意想要的格式,audio/mpeg就是mp3的格式~

        mediaRecorder.ondataavailable = function(e) {
          chunks.push(e.data);
        }
        mediaRecorder.onstop = function(evt) {
          blobResult = new Blob(chunks, { 'type' : 'audio/mpeg' });
  
        };

6、表單模式下的錄音類為啥要判斷inactive狀態(tài)呢?

因?yàn)?MediaRecorder?接口 有三個(gè)狀態(tài)?inactive,?recording,?paused

這三個(gè)狀態(tài)分別是設(shè)備閑置,設(shè)備使用,設(shè)備暫停,有點(diǎn)類似于window的未響應(yīng),當(dāng)我們想要操作麥克風(fēng)時(shí),此時(shí)麥克風(fēng)inactive了,那就無(wú)法響應(yīng)我們的請(qǐng)求,所以當(dāng)狀態(tài)為inactive時(shí),我們都return掉,使他不執(zhí)行我們的方法。

    // 結(jié)束錄音
    this.end = function () {
      // 當(dāng)錄音類處于不活躍狀態(tài)時(shí),停止操作
      if (mediaRecorder.state === 'inactive') return
      mediaRecorder.requestData()
      mediaRecorder.stop();
    };
    // 暫停錄音
    this.stop = function() {
      // 當(dāng)錄音類處于不活躍狀態(tài)時(shí),停止操作
      if (mediaRecorder.state === 'inactive') return
      mediaRecorder.pause()
    }
    // 恢復(fù)錄音
    this.again = function() {
      // 當(dāng)錄音類處于不活躍狀態(tài)時(shí),停止操作
      if (mediaRecorder.state === 'inactive') return
      mediaRecorder.resume()
    }

------有不懂的可以評(píng)論區(qū)聊聊噢~------文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-764582.html

到了這里,關(guān)于有趣且重要的JS知識(shí)合集(18)瀏覽器實(shí)現(xiàn)前端錄音功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 開(kāi)源語(yǔ)言模型的歷史和重要性;Edge瀏覽器將推出Bing AI重寫(xiě)文本功能

    開(kāi)源語(yǔ)言模型的歷史和重要性;Edge瀏覽器將推出Bing AI重寫(xiě)文本功能

    ?? AI新聞 ?? 微軟即將推出桌面版Microsoft Edge瀏覽器的Bing AI重寫(xiě)文本功能 摘要 :微軟最近在桌面版Microsoft Edge瀏覽器中引入了一個(gè)新功能,允許用戶使用Bing AI重寫(xiě)文本。用戶可以選擇不同的語(yǔ)氣、格式和長(zhǎng)度,然后通過(guò)重寫(xiě)按鈕來(lái)生成Bing AI的回應(yīng)。目前該功能正在向部分內(nèi)

    2024年02月14日
    瀏覽(25)
  • js獲取元素到可視區(qū)的距離/瀏覽器窗口滾動(dòng)距離/元素距離瀏覽器頂部距離

    1. js獲取元素距離可視區(qū)的各種距離 2. js獲取瀏覽器窗口滾動(dòng)距離 3. js獲取元素實(shí)際距離頁(yè)面距離(包括滾動(dòng)距離) (1).如果父輩元素中有定位的元素,那么就返回距離當(dāng)前元素最近的定位元素邊緣的距離。 (2).如果父輩元素中沒(méi)有定位元素,那么就返回相對(duì)于body邊緣距

    2024年02月12日
    瀏覽(22)
  • js控制瀏覽器前進(jìn)、后退、頁(yè)面跳轉(zhuǎn)

    在JavaScript中,你可以使用? window ?對(duì)象的? history ?對(duì)象來(lái)控制瀏覽器的歷史記錄。以下是一些常用的方法: 前進(jìn)和后退 : window.history.forward() : 前進(jìn)到歷史記錄中的下一個(gè)頁(yè)面。 window.history.back() : 返回歷史記錄中的上一個(gè)頁(yè)面。 window.history.go(n) : 跳轉(zhuǎn)到歷史記錄中的指定頁(yè)

    2024年01月20日
    瀏覽(20)
  • 運(yùn)行 Node.js 與瀏覽器 JavaScript

    瀏覽器和 Node.js 都使用 JavaScript 軟件語(yǔ)言 - 但字面上的 運(yùn)行時(shí)環(huán)境 是不同的。 Node.js(又名服務(wù)器端 JavaScript)與客戶端 JavaScript 有許多相似之處。它也有很多差異。 盡管兩者都使用 JavaScript 作為軟件語(yǔ)言,但我們可以重點(diǎn)關(guān)注一些關(guān)鍵差異,這些差異使兩者之間的軟件開(kāi)發(fā)

    2024年02月09日
    瀏覽(28)
  • 最新JS判斷是否是360瀏覽器方法

    最新JS判斷是否是360瀏覽器方法

    總所周知,360瀏覽器UA信息和谷歌瀏覽器完全一致,之前的諸多奇葩招數(shù)基本也都修復(fù)了 目前測(cè)試可用的監(jiān)測(cè)方案如下: 360瀏覽器修這玩意每次都挺快,不知道能用多久,2023年6月目前可用 原理就是檢測(cè)dll文件,這個(gè)文件360瀏覽器 正常版本 和 極速版本 都沒(méi)有 是根據(jù)網(wǎng)上代

    2024年02月15日
    瀏覽(28)
  • js判斷是否處于微信瀏覽器內(nèi)

    當(dāng)我們開(kāi)發(fā)網(wǎng)頁(yè)應(yīng)用或移動(dòng)應(yīng)用時(shí),經(jīng)常需要根據(jù)用戶當(dāng)前的環(huán)境做一些特殊處理。在這篇文章中,我們將探討如何使用 JavaScript 來(lái)判斷當(dāng)前頁(yè)面是否在微信瀏覽器內(nèi)打開(kāi)。 微信是一款非常流行的社交媒體應(yīng)用,擁有龐大的用戶群體。為了提供更好的用戶體驗(yàn),我們可能需要

    2024年02月08日
    瀏覽(21)
  • 【安全策略】前端 JS 安全對(duì)抗&瀏覽器調(diào)試方法

    【安全策略】前端 JS 安全對(duì)抗&瀏覽器調(diào)試方法

    1.1 什么是接口加密 如今這個(gè)時(shí)代,數(shù)據(jù)已經(jīng)變得越來(lái)越重要,網(wǎng)頁(yè)和APP是主流的數(shù)據(jù)載體。而如果獲取數(shù)據(jù)的接口沒(méi)有設(shè)置任何的保護(hù)措施,那么數(shù)據(jù)的安全性將面臨極大的威脅。不僅可能造成數(shù)據(jù)的輕易竊取和篡改,還可能導(dǎo)致一些重要功能的接口被惡意調(diào)用,引發(fā)DDoS、

    2024年01月21日
    瀏覽(29)
  • JS一些常用判斷(包括判斷是否是蘋(píng)果(ios)/安卓(Android)、是否是Safari瀏覽器、檢測(cè)瀏覽器語(yǔ)言等等)

    提示:文章寫(xiě)完后,目錄可以自動(dòng)生成,如何生成可參考右邊的幫助文檔 提示:這里可以添加本文要記錄的大概內(nèi)容: 參考鏈接 JS判斷客戶端是否是iOS或者Android:http://caibaojian.com/browser-ios-or-android.html

    2024年02月04日
    瀏覽(41)
  • 瀏覽器js打開(kāi)本地exe程序(超詳細(xì)、可用)

    瀏覽器js打開(kāi)本地exe程序(超詳細(xì)、可用)

    目的::打開(kāi)游覽器鏈接,彈出打開(kāi)本地exe操作 新建txt文件輸入以下代碼,可自行配置路徑,路徑必須為\\\\,且最后的 不可省略。 保存txt文件,并修改為xxx.reg文件。最后雙擊運(yùn)行 執(zhí)行HTML代碼即可實(shí)現(xiàn)目的? ?雙擊66666666666666666666

    2024年02月11日
    瀏覽(23)
  • js獲取用戶瀏覽器信息和ip地址以及位置

    js獲取用戶瀏覽器信息和ip地址以及位置

    效果如下 ? 效果如下 這里是在 vue中created生命周期中發(fā)送請(qǐng)求 ?返回輸入如下 ?

    2024年02月11日
    瀏覽(85)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包