2020-04-12

##小程序改基,大世界

###簡(jiǎn)介

· 小程序解決了什么問題

· 小程序技術(shù)棧

HTML/CSS/JavaScript ? NodeJS

移動(dòng)適配

HTTP協(xié)議/HTTPS

OAuth2

GIT

· 主流的小程序平臺(tái)

·類似?小程序的技術(shù)

Cordova:通過webview渲染怠缸,通過插件調(diào)?用系統(tǒng)服務(wù)

PWA:Service Worker和Push API

React Native/Weex:JavaScript通過JavaScriptCore等執(zhí)?行行樟蠕,并

通過Bridges和Native組件交互

Flutter:Dart直接與獨(dú)?立系統(tǒng)的UI庫(kù)進(jìn)?行行交互

###小程序的技術(shù)架構(gòu)

? ?文件結(jié)構(gòu)及其含義

.json 后綴的 JSON 配置?文件

.wxml 后綴的 WXML 模板?文件

.wxss 后綴的 WXSS 樣式?文件

.js 后綴的 JS 腳本邏輯?文件

?文件結(jié)構(gòu)及其含義:JSON

?文件結(jié)構(gòu)及其含義:WXML

本質(zhì)是HTML模版

有特定的標(biāo)簽

接管?一些簡(jiǎn)單的邏輯判斷

JS不不直接操作DOM貌亭,只負(fù)責(zé)set數(shù)據(jù)

?文件結(jié)構(gòu)及其含義: WXSS

提供rpx單位

精簡(jiǎn)的CSS

提供全局和局部的CSS

?文件結(jié)構(gòu)及其含義: JS

負(fù)責(zé)邏輯交互

APP 柬唯、Page、Component三個(gè)構(gòu)造函數(shù)

可調(diào)?用系統(tǒng)API

? 雙線程模型

? 生命周期

? 組件

? 其他

插件機(jī)制

云端函數(shù)

?小游戲

###開發(fā)發(fā)布流程

開發(fā)者在?小程序平臺(tái)注冊(cè)?小程序圃庭,以獲得APPID

初始化代碼并完成代碼倉(cāng)庫(kù)配置

開發(fā)代碼并調(diào)試

上傳并發(fā)布

###小程序的發(fā)展

多端同構(gòu)框架

?自動(dòng)化

硬件框架

云IDE

W3C?小程序?工作組

同構(gòu)框架

意義:?一次編寫適配多端,?一次迭代各端同步

利利?用Web的優(yōu)點(diǎn),以及對(duì)各個(gè)平臺(tái)進(jìn)?行行動(dòng)態(tài)適配

?小程序?自動(dòng)化

控制?小程序跳轉(zhuǎn)到指定?頁(yè)?面 ? 獲取?小程序?頁(yè)?面數(shù)據(jù)

獲取?小程序?頁(yè)?面元素狀態(tài)

觸發(fā)?小程序元素綁定事件

往 AppService 注?入代碼?片段 ? 調(diào)?用 wx 對(duì)象上任意接?口

硬件框架

云IDE

W3C小程序工作組

##Web前端點(diǎn)播直播入門

###什么是視頻丈屹?

1先蒋、格式與內(nèi)容

· 文件擴(kuò)展名≈媒體封裝格式(媒體容器類型)

· 媒體封裝格式≠音視頻編碼格式(使用了誰家的編碼器)

· 文件內(nèi)容:

1) 頭信息(格式业岁、時(shí)長(zhǎng)允耿、幀率念链、碼率君编、分辨率...)

2) 索引信息

3) 視頻數(shù)據(jù)

4) 音頻數(shù)據(jù)

5) 附加增強(qiáng)數(shù)據(jù)...

2兑燥、視頻數(shù)據(jù)

· 顯示器顏色呈現(xiàn)基于RGB(紅綠藍(lán))顏色空間模型

· 視頻領(lǐng)域大多基于YUV顏色空間做抽樣存儲(chǔ)

· 幀內(nèi)預(yù)測(cè)&幀間預(yù)測(cè)復(fù)用進(jìn)一步有效的壓縮數(shù)據(jù)

· P幀(前向預(yù)測(cè)幀)除师、B幀(雙向預(yù)測(cè)幀)搓侄、I幀(參考幀)

· 基于通用標(biāo)準(zhǔn)集N多技術(shù)于一身 --- 視頻編碼器

H.264(AVC)、H.265(HEVC)泊交、VP8乳讥、VP9...

3、音頻數(shù)據(jù)

· 聲音:不同振幅&頻率而產(chǎn)生的機(jī)械波廓俭;數(shù)字形式是一維波形

· 對(duì)自然中連續(xù)的聲波采樣云石,做數(shù)字化PCM存儲(chǔ)

· 揚(yáng)聲器還原PCM(脈沖編碼調(diào)制)數(shù)字信號(hào)為模擬音頻信號(hào)

· 音頻壓縮基本算法:預(yù)測(cè)、變換

· 基于通用標(biāo)準(zhǔn)集N多技術(shù)于一身 --- 音頻編碼器???????

AAC研乒、MP3...

4汹忠、傳輸協(xié)議

傳統(tǒng)場(chǎng)景

流媒體(直播)

· HLS:蘋果為利用現(xiàn)有CDN設(shè)施而發(fā)明的"流媒體"協(xié)議

· HTTP(S)-FLV:基于HTTP的流媒體協(xié)議

· RTMP、RTP/RTSP、TS宽菜、MMS...

點(diǎn)播傳輸

· HTTP(S):通過Range方式或參數(shù)方式完成Seek

Web端

·HTTP(S)谣膳、WS(S)、P2P...

5铅乡、播放器原理

· 解協(xié)議(加載數(shù)據(jù))

· 解封裝(解復(fù)用)

· 解碼

· 渲染

###好玩的WebAPI

1继谚、媒體兼容判斷

let videoEl = document.createElement("video");

let types = {

? 'mp4': 'audio/mp4',

? 'MP4': 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',

? 'webm': 'video/webm; codecs="vp8, vorbis"',

? 'ogg': 'video/ogg; codecs="theora, vorbis"',

? 'm3u8': 'application/vnd.apple.mpegURL',

? 'ts': 'video/mp2t; codecs="avc1.42E01E,mp4a.40.2"'

};

Object.keys(types).forEach(key => {

? const type = types[key];

? const ret = videoEl.canPlayType(type) || '不支持';

? console.log(key + ': ' + ret);

});

2、交互式視頻

let video = $('video');

video.ontimeupdate = ()=>{

? let {currentTime} = video;

? show(currentTime > 64 ? '.s2' : '.s1');

? hide(currentTime > 64 ? '.s1' : '.s2');

? if(

? ? (currentTime > 64 && currentTime < 65) ||

? ? (currentTime > 113 && currentTime < 114)

? ){

? ? video.pause();

? }

};

let ppBtn = $('paly_pause');

video.onplay = ()=>{

? ppBtn.innerText = '暫停';

};

video.onpause = ()=>{

? ppBtn.innerText = '播放';

};

ppBtn.onclick = ()=>{

? video[video.paused ? 'play' : 'pause' ]();

};

$('start').onclick = ()=>{

? video.currentTime = 1;

? video.play();

};

$('step').onclick = ()=>{

? video.currentTime = 60;

? video.play();

};

$('dream').onclick = ()=>{

? video.currentTime = 83;

? video.play();

};

$('drink').onclick = ()=>{

? video.currentTime = 116;

? video.play();

};

hide('.s2');

function show(sel){

? document.querySelectorAll(sel).forEach(el=>{

? ? el.style.display='inline'

? });

}

function hide(sel){

? document.querySelectorAll(sel).forEach(el=>{

? ? el.style.display='none'

? });

}

function $(id){

? return document.getElementById(id);

}

3阵幸、播放本地視頻文件

let iptFileEl = document.querySelector('input[type="file"]');

let videoEl = document.querySelector('video');

iptFileEl.onchange = e =>{

? let file = iptFileEl.files && iptFileEl.files[0];

? playFile(file);

};

function playFile(file){

? if(file){

? ? let fileReader = new FileReader();

? ? fileReader.onload = evt => {

? ? ? if(FileReader.DONE == fileReader.readyState){

? ? ? ? videoEl.src = fileReader.result;

? ? ? }else{

? ? ? ? console.log('FileReader Error:', evt);

? ? ? }

? ? }

? ? fileReader.readAsDataURL(file);

? }else{

? ? videoEl.src = '';

? }

}

4花履、播放硬件資源(調(diào)用攝像頭或麥克風(fēng))

const getUserMediaPromise = options => new Promise((resolve, reject) => {

? const nvgt = window.navigator;

? if(nvgt) {

? ? if(nvgt.mediaDevices && nvgt.mediaDevices.getUserMedia) {

? ? ? return nvgt.mediaDevices.getUserMedia(options).then(resolve, reject);

? ? }

? ? const getUserMedia = nvgt.getUserMedia || nvgt.webkitGetUserMedia || nvgt.mozGetUserMedia;

? ? if(getUserMedia) {

? ? ? return getUserMedia(options, resolve, reject)

? ? }

? }

? reject('當(dāng)前環(huán)境不支持獲取媒體設(shè)備。');

});

let streamTrack;

const video = document.querySelector('video');

document.querySelector('#play').onclick = () => {

? getUserMediaPromise({

? ? audio: false,

? ? video: true

? }).then(stream => {

? ? video.srcObject = stream;

? ? streamTrack = stream.getTracks()[0];

? },

? err => {

? ? console.log('getUserMedia error: [' + err.name + '] ' + err.message)

? });

};

document.querySelector('#stop').onclick = () => {

? streamTrack && streamTrack.stop();

};

const box = document.querySelector('div');

document.querySelector('#sketch').onclick = () => {

? box.className = box.className ==='' ? 'sketch' : '';

};

5挚赊、實(shí)現(xiàn)視頻錄制

const getUserMediaPromise = options => new Promise((resolve, reject) => {

? const nvgt = window.navigator;

? if(nvgt) {

? ? if(nvgt.mediaDevices && nvgt.mediaDevices.getUserMedia) {

? ? ? return nvgt.mediaDevices.getUserMedia(options).then(resolve, reject);

? ? }

? ? const getUserMedia = nvgt.getUserMedia || nvgt.webkitGetUserMedia || nvgt.mozGetUserMedia;

? ? if(getUserMedia) {

? ? ? return getUserMedia(options, resolve, reject)

? ? }

? }

? reject('當(dāng)前環(huán)境不支持獲取媒體設(shè)備诡壁。');

});

const video = document.querySelector('#preview');

let cameraStream;

const opencameraBtn = document.querySelector('#opencamera');

const closecameraBtn = document.querySelector('#closecamera');

const recordBtn = document.querySelector('#record');

const stopRecordBtn = document.querySelector('#stoprecord');

const playBtn = document.querySelector('#play');

const downloadBtn = document.querySelector('#download');

opencameraBtn.onclick = () => getUserMediaPromise({

? audio: false,

? video: true

}).then(

? stream => {

? ? cameraStream = video.srcObject = stream;

? ? opencameraBtn.disabled = true;

? ? closecameraBtn.disabled = false;

? ? recordBtn.disabled = false;

? },

? err => {

? ? console.log('getUserMedia error: [' + err.name + '] ' + err.message)

? }

);

closecameraBtn.onclick = () => {

? cameraStream && cameraStream.getTracks()[0].stop();

? cameraStream = null;

? opencameraBtn.disabled = false;

? closecameraBtn.disabled = true;

? stopRecordBtn.onclick();

};

let mediaRecorder;

let recordedBlobs;

const mimeType = ['video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm', ''].find(type => {

? return MediaRecorder.isTypeSupported(type);

});

// console.log('mimeType', mimeType);

recordBtn.onclick = () => {

? recordedBlobs = [];

? try {

? ? mediaRecorder = new MediaRecorder(cameraStream, { mimeType });

? } catch(e) {

? ? alert('Exception while creating MediaRecorder: ' + e + '. mimeType: ' + mimeType);

? ? return;

? }

? recordBtn.disabled = true;

? stopRecordBtn.disabled = false;

? playBtn.disabled = true;

? downloadBtn.disabled = true;

? mediaRecorder.onstop = evt => {

? ? console.log('Recorder stopped');

? };

? mediaRecorder.ondataavailable = function(event) {

? ? if (event.data && event.data.size > 0) {

? ? ? recordedBlobs.push(event.data);

? ? }

? };

? mediaRecorder.start(20); // 單次收集數(shù)據(jù)毫秒時(shí)長(zhǎng),ondataavailable 觸發(fā)頻率時(shí)長(zhǎng)間隔

};

const recordedVideo = document.querySelector('#recorded');

stopRecordBtn.onclick = () => {

? mediaRecorder && mediaRecorder.stop();

? mediaRecorder = null;

? // console.log('Recorded Blobs: ', recordedBlobs);

? recordedVideo.controls = true;

? playBtn.disabled = false;

? downloadBtn.disabled = false;

? stopRecordBtn.disabled = true;

? if(!cameraStream) {

? ? recordBtn.disabled = true;

? }

};

const getRecordedBlobUrl = () => {

? const superBuffer = new Blob(recordedBlobs, {type: mimeType.split(';')[0]});

? return window.URL.createObjectURL(superBuffer);

};

playBtn.onclick = () => {

? recordedVideo.src = getRecordedBlobUrl();

}

downloadBtn.onclick = () => {

? var a = document.createElement('a');

? a.style.display = 'none';

? a.href = getRecordedBlobUrl();

? a.download = 'test.webm';

? document.body.appendChild(a);

? a.click();

? setTimeout(function() {

? ? document.body.removeChild(a);

? ? window.URL.revokeObjectURL(url);

? }, 100);

}

6咬腕、播放JS拉取的媒體數(shù)據(jù)

const video = document.querySelector('video');

const fetchMp4 = (url, cb) => {

? const xhr = new XMLHttpRequest();

? xhr.open('get', url);

? xhr.responseType = 'arraybuffer';

? xhr.onload = function () {

? ? cb(xhr.response);

? };

? xhr.send();

};

const assetURL = 'https://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4';

const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';

// 創(chuàng)建動(dòng)態(tài)媒體源欢峰,并關(guān)聯(lián)到video元素上

const mediaSource = new MediaSource();

video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', () => {

? const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);

? // 拉取數(shù)據(jù)

? fetchMp4(assetURL, buf => {

? ? sourceBuffer.addEventListener('updateend', () => {

? ? ? // 媒體流傳輸完畢

? ? ? mediaSource.endOfStream();

? ? ? // video.play();

? ? });

? ? // 將數(shù)據(jù)喂給 Video -- 注意這里只是一次性輸入整個(gè)MP4數(shù)據(jù)

? ? sourceBuffer.appendBuffer(buf);

? });

});

###Web端點(diǎn)播直播&播放器解決方案

1、點(diǎn)播直播的區(qū)別

應(yīng)用流程

· 點(diǎn)播:創(chuàng)作者 => 上傳 => 轉(zhuǎn)碼 => 存儲(chǔ) <=> CDN分發(fā) <=> 觀眾

· 直播:創(chuàng)作者 => 推流 <=> 存儲(chǔ) <=> 轉(zhuǎn)碼 <=> CDN分發(fā) <=> 觀眾

媒體類型的選擇

· HTTP(S)-MP4.. 點(diǎn)播服務(wù)

· HTTP(S)-FLV 點(diǎn)播涨共、直播

· HTTP(S)-HLS 點(diǎn)播纽帖、直播(高延遲)

2、播放器解決方案

原生瀏覽器支持的

· 直接走原生Video播放

原生瀏覽器不支持的

· 協(xié)議或容器類型不支持

JS解協(xié)議下載數(shù)據(jù)举反、解容器懊直、重新封裝,然后通過MSE喂給Video解碼火鼻、渲染播放

例如Web端播放FLV室囊、HLS:http://chimee.org

· 解碼器不支持

JS下載數(shù)據(jù),WASM 解容器魁索、解碼融撞,通過 WebGL&WebAudio 渲染播放

例如Web端播放HEVC編碼視頻:https://zyun.#/developer/doc?did=QHWWPlayer

· 有解密需求的

參考前兩條,在解容器之后對(duì)每幀數(shù)據(jù)啟用解密邏輯粗蔚。

##前端代碼的自我修養(yǎng)

如何衡量代碼質(zhì)量的好壞尝偎?

衡量代碼質(zhì)量的唯一有效標(biāo)準(zhǔn):WTF/min —— Robert C. Martin

代碼的自我修養(yǎng)

· 代碼規(guī)范

· 格式

· 流程化

代碼規(guī)范:

安裝Eslint:yarn global add eslint

使用Eslint規(guī)范代碼

流程化:

如何優(yōu)雅地提交代碼

· git commit message規(guī)范

· 合并提交

##技術(shù)翻譯:進(jìn)階的直梯

1、翻譯類型

文學(xué)翻譯 非文學(xué)翻譯

藝術(shù)成分多一些 科學(xué)成分多一些

需要更多的靈感 需要更多的勤奮

責(zé)任小一些 責(zé)任大一些

2鹏控、技術(shù)翻譯的意義

翻譯技術(shù)文章致扯,學(xué)習(xí)新技術(shù)思想

翻譯技術(shù)文檔,掌握標(biāo)準(zhǔn)和工具

翻譯技術(shù)圖書当辐,獲得名聲和報(bào)酬

3抖僵、技術(shù)翻譯的標(biāo)準(zhǔn)

準(zhǔn)確、地道缘揪、簡(jiǎn)潔

4耍群、技術(shù)翻譯的方法

消化吸收原文

母語地道表達(dá)

就是翻譯意思

5义桂、技術(shù)翻譯要堅(jiān)持技術(shù)驅(qū)動(dòng)

示例原文

An object literal can only use a symbol as a property inside the computed property syntax.

let s1 = Symbol('foo'),

let o = {

? [s1]: 'foo val'

};

// Also valid:

// o[s1] = 'foo val';

console.log(o);

// {Symbol{foo}: foo val}

參考譯文

對(duì)象字面量只能在計(jì)算屬性語法中使用符號(hào)作為屬性。

語法中使用符號(hào)作為屬性世吨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末澡刹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子耘婚,更是在濱河造成了極大的恐慌罢浇,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沐祷,死亡現(xiàn)場(chǎng)離奇詭異嚷闭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)赖临,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門胞锰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兢榨,你說我怎么就攤上這事嗅榕。” “怎么了吵聪?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵凌那,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我吟逝,道長(zhǎng)帽蝶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任块攒,我火速辦了婚禮励稳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘囱井。我一直安慰自己驹尼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布庞呕。 她就那樣靜靜地躺著新翎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪千扶。 梳的紋絲不亂的頭發(fā)上料祠,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天骆捧,我揣著相機(jī)與錄音澎羞,去河邊找鬼。 笑死敛苇,一個(gè)胖子當(dāng)著我的面吹牛妆绞,可吹牛的內(nèi)容都是我干的顺呕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼括饶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼株茶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起图焰,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤启盛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后技羔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體僵闯,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年藤滥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鳖粟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拙绊,死狀恐怖向图,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情标沪,我是刑警寧澤榄攀,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站谨娜,受9級(jí)特大地震影響航攒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趴梢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一漠畜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坞靶,春花似錦憔狞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尿这,卻和暖如春簇抵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背射众。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工碟摆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叨橱。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓典蜕,卻偏偏與公主長(zhǎng)得像断盛,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子愉舔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容