好程式設計師web前端培訓分享node學習筆記系列之四十一
好程式設計師 web前端培訓分享 node學習筆記 系列之 四十一
一、手動封裝body-parser中介軟體 cookie-parser中介軟體
1、封裝axios請求方式
body-parser
const qs = require( "querystring" ); var bodyparse = ( function bodyparse() {
function common(type) {
return (req, res, next) => {
let contentType = req.headers[ "content-type" ];
if (contentType == "application/json" || contentType == "application/x-www-form-urlencoded" ){
let str = "" ;
req.on( "data" ,(data)=>{
str += data;
})
req.on( "end" ,()=>{
if (contentType == "application/json" ){
req.body = JSON.parse(str);
next();
} else if ( contentType == "application/x-www-form-urlencoded" ){
req.body = qs.parse(str);
next();
}
next();
})
} else {
next();
}
}
}
//解析appliaction/json function json() {
let type = "json"
return common(type)
}
//解析appliaction/x-www-form-urlencoded function urlencoded() {
let type = "urlencoded" ;
return common(type)
}
return { json, urlencoded }})() module.exports = bodyparse;
cookie-parser
const cookieparse = function (){
return (req,res,next)=>{
let cookies = req.headers.cookie;
let obj = cookies.split( "; " ).reduce((prev,curr)=>{
var key = curr.split( "=" )[ 0 ];
var val = curr.split( "=" )[ 1 ];
prev[key] = val;
return prev;
},{})
req.headers.cookie = obj;
next();
}}module.exports = cookieparse;
二、express原理解析
1、app.use的作用以及實現
const http = require( "http" ) const url = require( "url" ); const path = require( "path" ); const fs = require( "fs" ); const express = () => {
//將所有註冊的事件新增到routesMap中去 var routesMap = {
get : {
},
post : {
}
}
//app這個函式中做的執行 var app = function (req, res) {
//獲取使用者請求的路徑 var pathname = url.parse(req.url).pathname;
//獲取使用者請求的方式 var method = req.method.toLowerCase();
if (pathname !== "/favicon.ico" ) {
//next函式用來執行下一個中介軟體 var next = function () {
var handle;
//執行是沒有路徑的函式 while (handle = routesMap.all.shift()) {
handle(req, res, next)
}
}
next();
//執行app.use帶路徑的函式 for ( var key in routesMap) {
//判斷路徑是否與使用者請求的路徑相同 if (key === pathname) {
routesMap[key](req, res, next);
break ;
}
}
//判斷使用者是否是get請求 if (method == "get" ) {
//如果是get請求則找到get請求相對應得路徑 執行對應的函式 for ( var key in routesMap.get) {
if (key == pathname) {
routesMap.get[key](req, res, next);
break ;
}
}
} else if (method == "post" ) {
}
}
}
//註冊事件 app.use = function () {
//判斷use中的第一個引數是路徑還是一個函式 if ( typeof arguments[ 0 ] === "string" ) {
routesMap[arguments[ 0 ]] = arguments[ 1 ]
} else if ( typeof arguments[ 0 ] === "function" ) {
//建議all這個key值寫成Symbol if ( ! routesMap.all) {
routesMap.all = [];
}
routesMap.all.push(arguments[ 0 ]);
}
}
//註冊事件 app.get = function (path, callback) {
routesMap.get[path] = callback;
}
//建立服務 app.listen = function (port, callback) {
http.createServer(app).listen(port, callback)
}
return app;} //靜態資源訪問 express. static = function (staticPath) {
function getFile(filePath) {
return fs.readFileSync(filePath);
}
return (req, res) => {
var { pathname } = url.parse(req.url, true );
//獲取檔案的字尾 var ext = pathname.substring(pathname.lastIndexOf( "." ));
if (pathname === "/" ) {
res.writeHead( 200 , { "content-type" : "text/html;charset=utf8" });
res.end(getFile(path.join(staticPath, "index.html" )))
} else if (ext === ".css" ) {
res.writeHead( 200 , { "content-type" : "text/css;charset=utf8" });
res.end(getFile(path.join(staticPath, pathname)));
} else if (ext === ".js" ) {
res.writeHead( 200 , { "content-type" : "application/x-javascript;charset=utf8" });
res.end(getFile(path.join(staticPath, pathname)));
} else if ( /.*\.(jpg|png|gif)/ .test(ext)) {
res.writeHead( 200 , { "content-type" : `image/${ RegExp .$1 };charset=utf8` });
res.end(getFile(path.join(staticPath, pathname)));
} else if (ext === ".html" ) {
res.writeHead( 200 , { "content-type" : "text/html;charset=utf8" });
res.end(getFile(path.join(staticPath, pathname)));
}
}} module.exports = express;
三、express-generator生成器以及程式碼解析
1、app.js解析
2、www檔案解析
3、ejs的基本使用
用<% … %> 開始符和結束符之間寫js程式碼
用<%= … %>輸出變數資料 變數若包含 '<' '>' '&'等字元 會被轉義
用<%- … %>輸出變數(html的解析前面需要加-) 不轉義
用<%- include('user/show') %>引入其他模板
包含 ./user/show.ejs
用<%# some comments %>來註釋,不執行不輸出
<%% 轉義為 '<%'<% ... -%> 刪除新的空白行模式?
<%_ … _%> 刪除空白符模式開始符和結束符內部不可以巢狀
四、前端渲染和後端渲染的區別
後端渲染HTML的情況下,瀏覽器會直接接收到經過伺服器計算之後的呈現給使用者的最終的HTML字串,這裡的計算就是伺服器經過解析存放在伺服器端的模板檔案來完成的,在這種情況下,瀏覽器只進行了HTML的解析,以及透過作業系統提供的操縱顯示器顯示內容的系統呼叫在顯示器上把HTML所代表的影像顯示給使用者。
前端渲染就是指瀏覽器會從後端得到一些資訊,這些資訊或許是適用於題主所說的angularjs的模板檔案,亦或是JSON等各種資料交換格式所包裝的資料,甚至是直接的合法的HTML字串。這些形式都不重要,重要的是,將這些資訊組織排列形成最終可讀的HTML字串是由瀏覽器來完成的,在形成了HTML字串之後,再進行顯示
五、用所學的express生成器+ejs做一個簡單的列表頁
六 、socket的基本使用
1、什麼是socket?
網路上兩個程式透過一個雙向的通訊連線實現資料交換,這個連線的一端稱為socket
2、http請求與socket的區別
1、在以前我們實現資料交換已經有了HTTP協議,為什麼還要學習socket? 回顧:當輸出
的時候瀏覽器執行了那些操作?
2、http通訊的
特點:
1、連線屬於非永續性連線:TCP的三次握手
2、客戶端只能訪問服務端,服務端無法訪問客戶端,屬於單項通訊
TCP三次握手: TCP三次握手過程中不傳遞資料,只為同步連線雙方的序列號和確認號傳遞資料,在握手後服務端和客戶端才開始傳輸資料,在理想狀態下,TCP連線一旦建立,在通訊的雙方中任何一方主動斷開連線之前TCP連線會一直保持下去。
socket通訊
特點:
1、永續性連線
2、雙向通訊,客戶端能訪問服務端,服務端也能訪問客戶端
socket是對TCP/IP協議的封裝,socket只是一個介面而不是一個協議,透過Socket我們才能使用TCP/IP/UDP協議
3、透過node內建模組net實現簡單版聊天
1、socket連線需要由2個節點:
(1)clientSocket
(2)serverSocket
2、文字流:readline
const net = require( "net" ); const server = net.createServer(); const clients = []; //當有人連線服務端的時候回觸發當前函式 server.on( "connection" ,(client)=>{
//給每一個使用者新增一個唯一的標識 client.id = clients.length;
clients.push(client);
//將客戶端的訊息轉發給所有的使用者 client.on( "data" ,(data)=>{
clients.forEach(item=>{
//判斷使用者是否存在 if (item) item.write( "服務端:" + data);
})
})
//判斷使用者是否退出群聊 client.on( "close" ,()=>{
clients[client.id] = null ;
}) }) server.listen( 9000 ); const net = require( "net" ); const client = new net.Socket(); //建立I/o模型 建立出入和輸出流 const readline = require( "readline" ); //建立 const rl = readline.Interface({
input : process.stdin,
output : process.stdout}) //客戶端連線服務端 client.connect( 9000 , () => {
client.on( "data" , (data) => {
console.log(data.toString());
})}) //獲取終端的內容將內容轉發到服務端 rl.on( "line" , (val) => {
client.write(val);})
七、webSocket的基本使用
const WebSocket = require( 'ws' ); //建立服務 const server = new WebSocket.Server({ port : 9000 }); //監控使用者連線 server.on( 'connection' , (client,req)=>{
var ip = req.connection.remoteAddress;
//監聽客戶端傳遞到服務端的訊息 client.on( 'message' , (data)=>{
//將訊息轉發給所有的使用者 server.clients.forEach((item)=>{
//判斷使用者是否是連線的狀態 if (item.readyState === WebSocket.OPEN) {
item.send(ip + ":" + data);
}
});
});});
<! DOCTYPE html >< html lang = "en" >< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta http - equiv = "X-UA-Compatible" content = "ie=edge" >
< title > Document < /title> < /head> < body >
< input type = "text" id = "txt" >
< button id = "btn" > 點選 < /button>
< ul id = "list" >< /ul> < /body> < /html> < script >
var client = new WebSocket( "ws://10.60.15.150:9000" );
var txt = document .getElementById( "txt" );
var list = document .getElementById( "list" );
var btn = document .getElementById( "btn" );
//接受服務端訊息 onmessage client.onmessage = function (e){
var li = document .createElement( "li" );
li.innerText = e.data;
list.appendChild(li);
li.scrollIntoView();
}
//向服務端傳送訊息 send btn.onclick = function (){
var val = txt.value;
client.send(val);
txt.value = "" ;
} < /script>
八、 的基本使用
var express = require( 'express' ) var app = express(); //檔案在伺服器執行 var http = require( 'http' ) var server = http.createServer(app); var path = require( "path" ) //因為我們要做永續性通訊 因此不能夠用http連線 http連線與socket.io進相關聯 var io = require( "socket.io" )(server);app.use(express. static (path.join(__dirname, "./public" ))) //當使用者連線的時候觸發的函式 io.on( 'connection' , (socket)=>{
console.log( 'a user connected' );
//接受客戶端訊息 將訊息轉發給所有使用者 socket.on( "sendMessage" ,(mes)=>{
io.emit( "message" ,mes)
})
//當使用者斷開連線的時候 socket.on( 'disconnect' , function (){
console.log( 'user disconnected' );
});});server.listen( 3000 , function (){
console.log( 'listening on *:3000' );});
九、利用websocket實現一個聊天室
1、多人聊天
2、圖片傳送
3、表情傳送
var express = require( 'express' ) var app = express(); //檔案在伺服器執行 var http = require( 'http' ) var server = http.createServer(app); var path = require( "path" ) //因為我們要做永續性通訊 因此不能夠用http連線 http連線與socket.io進相關聯 var io = require( "socket.io" )(server);app.use(express. static (path.join(__dirname, "./public" ))) var users = []; //當使用者連線的時候觸發的函式 io.on( 'connection' , (socket)=>{
//監聽使用者連線 socket.on( "system" ,(username,type)=>{
if (users.includes(username)){
socket.emit( "login" , 0 )
} else {
socket.userIndex = users.length;
socket.username = username;
users.push(username);
io.emit( "login" , 1 ,username)
}
})
socket.emit( "userList" ,users);
socket.on( "ClientsendMessage" ,(usename,message)=>{
socket.broadcast.emit( "serverSendMessage" ,usename,message)
})
socket.on( "sendImg" ,(username,base64Img)=>{
socket.broadcast.emit( "serverSendImg" ,usename,base64Img)
}) });server.listen( 3000 , function (){
console.log( 'listening on *:3000' );}); <! doctype html >< html > < head >
< title > Socket.IO chat < /title>
< link rel = "stylesheet" href = "./css/iconfont/iconfont.css" >
< style >
* { margin : 0 ; padding : 0 ; box - sizing : border - box; }
ul,li{ list - style : none; }
html, body { font : 13 px Helvetica, Arial; height : 100 % ; }
form { background : # 000 ; padding : 3 px; position : fixed; bottom : 0 ; width : 100 % ; }
form input { border : 0 ; padding : 10 px; width : 90 % ; margin - right : .5 % ; }
form button { width : 9 % ; background : rgb( 130 , 224 , 255 ); border : none; padding : 10 px; }
# messages { list - style - type : none; margin : 0 ; padding : 0 ; }
# messages li { padding : 5 px 10 px; }
# messages li : nth - child(odd) { background : # eee; }
# action { width : 100 % ; height : 30 px; display : flex; align - items : center; }
# action input[type = 'color' ] { width : 40 px; height : 30 px; }
# upload, # fontColor { width : 40 px; height : 30 px; position : relative; }
# action input[type = 'file' ],
# fontColor input[type = "color" ] { width : 40 px; height : 30 px; position : absolute; left : 0 % ; top : 0 ; opacity : 0 ; z - index : 5 ;}
# action i, # fontColor i { width : 100 % ; height : 100 % ; position : absolute; left : 0 ; top : 0 ; color : # fff; font - size : 20 px;}
# mask { width : 100 % ; height : 100 % ; background : rgba( 0 , 0 , 0 , .3 ); position : absolute; z - index : 10 ;}
# content{ width : 100 % ; height : 100 % ; display : flex; justify - content : space - between;}
# content ul : nth - child( 2 ){ width : 200 px; height : 100 % ; border - left : 1 px solid # ccc; }
# userList { overflow : scroll; }
# userList li{ line - height : 30 px; border - bottom : 1 px solid # bbb; width : 100 % ; }
.userDate{ color : green; line - height : 20 px; font - size : 18 px; }
.userInfo{ color : # 000 ; line - height : 20 px; font - size : 14 px; }
# messages > div{ min - height : 60 px; }
# system{ color : # c33; font - size : 18 px; }
< /style> < /head> < body >
< div id = "mask" >< /div>
< div id = "content" >
< ul id = "messages" >< /ul>
< ul id = "userList" >
< li > 使用者列表 < /li>
< /ul>
< /div>
< form id = "form" >
< div id = "action" >
< div id = "fontColor" >
< input type = "color" >
< i class= "iconfont" >& # xec85; < /i>
< /div>
< div id = "upload" >
< input type = "file" id = "file" >
< i class= "iconfont" >& # xe674; < /i>
< /div>
< ul >< /ul>
< /div>
< input id = "m" autocomplete = "off" />
< input type = "submit" value = "提交" >
< /form> < /body> < /html> < script src = "/socket.io/socket.io.js" >< /script> < script src = " >< /script> < script src = "./js/index.js" >< /script>
index.js
class SocketAlley {
constructor() {
this .mask = $( "#mask" );
this .userListEl = $( "#userList" );
this .messages = $( "#messages" );
this .socket = io();
this .init();
}
init() {
if ( ! sessionStorage.getItem( "status" )) {
this .username = window .prompt( "請輸入您的姓名" );
if ( this .username) {
sessionStorage.setItem( "status" , this .username);
//當使用者連線進來的時候通知伺服器 this .socket.emit( "system" , this .username, "login" )
//檢測是否連線成功 this .socket.on( "login" , (data, username) => {
if (data == 1 ) {
alert( "連線成功" );
this .mask.hide();
//全域性通知 var div = $( "<div></div>" );
var str = username + "進入聊天室"
div.text(str);
this .messages.append(div);
} else {
alert( "使用者名稱重複請求重新編寫" );
}
})
}
} else {
this .mask.hide();
this .username = sessionStorage.getItem( "status" );
this .socket.on( "login" , (data, username) => {
//全域性通知 var div = $( "<div></div>" );
var str = username + "進入聊天室"
div.text(str);
this .messages.append(div);
})
}
this .userList();
this .serverMessage();
this .userSendInfo();
this .sendImg();
}
userList() {
this .socket.on( "userList" , this .handleUserListSucc.bind( this ))
}
handleUserListSucc(data) {
data.forEach( this .handleUserListEach.bind( this ))
}
handleUserListEach(item) {
var li = $( "<li></li>" );
li.text(item);
this .userListEl.append(li);
}
userSendInfo() {
$( "#form" ).on( "submit" , this .handleUserSendInfo.bind( this ))
}
handleUserSendInfo(e) {
e.preventDefault();
var val = $( "#m" ).val();
this .infoStyle( this .username, val);
//向服務端傳送訊息 this .socket.emit( "ClientsendMessage" , this .username, val);
}
serverMessage() {
this .socket.on( "serverSendMessage" , (username, message) => {
this .infoStyle(username, message);
})
this .socket.on( "serverSendImg" , (username, message) => {
this .infoImg(username, message);
})
}
infoImg(username, message) {
var parentDiv = $( "<div></div>" );
var childDiv = $( "<div></div>" );
var contentDiv = $( "<div></div>" );
var d = new Date ();
if ( /(\d{2}:\d{2}:\d{2})/ .test(d)) {
childDiv.text(username + RegExp .$1);
var img = $( "<img/>" );
img.attr( "src" ,message);
contentDiv.append(img);
parentDiv.append(childDiv);
parentDiv.append(contentDiv)
this .messages.append(parentDiv);
parentDiv[ 0 ].scrollIntoView();
}
}
infoStyle(username, message) {
var parentDiv = $( "<div></div>" );
var childDiv = $( "<div></div>" );
var contentDiv = $( "<div></div>" );
var d = new Date ();
if ( /(\d{2}:\d{2}:\d{2})/ .test(d)) {
childDiv.text(username + RegExp .$1);
contentDiv.text(message);
parentDiv.append(childDiv);
parentDiv.append(contentDiv)
this .messages.append(parentDiv);
parentDiv[ 0 ].scrollIntoView();
}
}
sendImg() {
$( "#file" ).on( "change" , this .sendImgCb.bind( this ))
}
sendImgCb() {
var _this = this ;
//只能從原生JS中拿到file物件 var file = $( "#file" )[ 0 ].files[ 0 ];
//將file物件轉換dataurl(base64的檔案形式) var fileReader = new FileReader()
fileReader.onload = function (e) {
_this.socket.emit( "sendImg" , _this.username, e.target.result);
_this.infoImg(_this.username, e.target.result)
}
//將file轉換成dataUrl的形式 fileReader.readAsDataURL(file);
}} new SocketAlley();
十、利用socket實現一個簡單版的多人點餐功能
const express = require( "express" ); const app = express(); const http = require( "http" ); const server = http.createServer(app); const io = require( "socket.io" )(server); const path = require( "path" );app.use(express. static (path.join(__dirname, "./public" ))) io.on( "connection" , (socket) => {
socket.on( 'add' , (data) => {
socket.broadcast.emit( "serverAdd" ,data);
})
socket.on( 'reducer' , (data) => {
socket.broadcast.emit( "serverReducer" ,data);
})}) server.listen( 9000 ) <! DOCTYPE html >< html lang = "en" > < head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta http - equiv = "X-UA-Compatible" content = "ie=edge" >
< title > Document < /title>
< link rel = "stylesheet" href = "./css/reset.css" >
< style >
# goodsList {
width : 100 % ;
height : 100 % ;
padding : .1 rem;
}
.goodsItem {
display : flex;
width : 100 % ;
padding : .2 rem;
}
.goodsItem > div : nth - child( 1 ) {
margin - right : .2 rem;
}
.goodsItem img {
width : 2 rem;
height : 2.5 rem;
}
.goodsDes {
flex : 1 ;
display : flex;
justify - content : space - between;
flex - direction : column;
}
.goodsDes > div : nth - child( 3 ) {
display : flex;
}
.goodsDes > div : nth - child( 3 ) .reducer {
width : 30 px;
height : 30 px;
text - align : center;
line - height : 30 px;
background : # ccc;
color : # fff;
font - size : 16 px;
}
.goodsDes > div : nth - child( 3 ) .add {
width : 30 px;
height : 30 px;
text - align : center;
line - height : 30 px;
background : # ccc;
color : # fff;
font - size : 16 px;
}
.goodsDes > div : nth - child( 3 ) input {
width : 80 px;
height : 30 px;
border : 0 ;
}
< /style> < /head> < body >
<!--
1 、 需求評審
2 、 (需求肯定出來了)前後端開會 -> 定義介面(後端為主 前端為輔) 你寫程式碼的速度 * 需求的難易程度 * 1.5 = 模組開發的時間 cnpm install json - server - g json - server中的增刪改查 查 : GET 增 : POST 刪 : delete
改 : patch -->
< div id = "goodsList" >
< /div> < /body> < /html> < script src = "/socket.io/socket.io.js" >< /script> < script src = " >< /script> < script >
class Goods {
constructor() {
this .socket = io();
}
init() {
this .getGoods();
this .watchServer();
}
getGoods() {
$.ajax({
type : "get" ,
url : " ,
success : this .handleGetGoodsSucc.bind( this )
})
}
handleGetGoodsSucc(data) {
var str = "" ;
for ( var i = 0 ; i < data.length; i ++ ) {
str += `<div data-id="${ data[i].id }"> <div> <img src="${ data[i].goodsPic }" > </div> <div> <div>${ data[i].goodsName }</div> <div>單價:<span data-price="${ data[i].price }">${ data[i].price }</span>$</div> <div> <div>-</div> <input type="text" value="${ data[i].num }"> <div>+</div> </div> </div> </div> `
}
$( "#goodsList" ).html(str);
this .add();
this .reducer();
}
add() {
$( ".add" ).each( this .handleAddEach.bind( this ))
}
handleAddEach(index) {
$( ".add" ).eq(index).on( "click" , this .handleAddCb.bind( this , index))
}
handleAddCb(index) {
var n = $( ".add" ).eq(index).prev().attr( "value" );
var id = $( ".add" ).eq(index).parent().parent().parent().attr( "data-id" );
n ++ ;
$( ".add" ).eq(index).prev().attr( "value" , n);
var price = $( ".add" ).eq(index).parent().parent().find( "div" ).eq( 1 ).find( "span" ).attr( "data-price" );
$( ".add" ).eq(index).parent().parent().find( "div" ).eq( 1 ).find( "span" ).text(price * n)
//socket部分 this .socket.emit( "add" , { id : id, num : n });
}
reducer() {
$( ".reducer" ).each( this .handleReducerEach.bind( this ))
}
handleReducerEach(index) {
$( ".reducer" ).eq(index).on( "click" , this .handleReducerCb.bind( this , index))
}
handleReducerCb(index) {
var n = $( ".reducer" ).eq(index).next().attr( "value" );
var id = $( ".reducer" ).eq(index).parent().parent().parent().attr( "data-id" );
if (n == 1 ) {
n = 1 ;
} else {
-- n;
this .socket.emit( "reducer" , { id : id, num : n });
}
$( ".reducer" ).eq(index).next().attr( "value" , n);
var price = $( ".reducer" ).eq(index).parent().parent().find( "div" ).eq( 1 ).find( "span" ).attr( "data-price" );
$( ".reducer" ).eq(index).parent().parent().find( "div" ).eq( 1 ).find( "span" ).text(price * n)
}
watchServer() {
this .socket.on( "serverAdd" , this .handleServerAddSucc.bind( this ));
this .socket.on( "serverReducer" , this .handleServerReducerSucc.bind( this ))
}
handleServerAddSucc(data) {
$( ".add" ).each( this .handleAddEachServer.bind( this , data))
}
handleAddEachServer(data, index) {
var id = $( ".add" ).eq(index).parent().parent().parent().attr( "data-id" );
if (id == data.id) {
var val = $( ".add" ).eq(index).prev().val();
$( ".add" ).eq(index).prev().val( Number (data.num));
}
}
handleServerReducerSucc(data) {
$( ".reducer" ).each( this .handleReducerEachServer.bind( this , data))
}
handleReducerEachServer(data, index) {
var id = $( ".reducer" ).eq(index).parent().parent().parent().attr( "data-id" );
if (id == data.id) {
var val = $( ".reducer" ).eq(index).next().val();
$( ".reducer" ).eq(index).next().val( Number (data.num));
}
}
}
new Goods().init(); < /script>
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2686761/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 好程式設計師web前端培訓分享node學習筆記程式設計師Web前端筆記
- 好程式設計師web前端培訓分享JavaScript學習筆記之設計模式程式設計師Web前端JavaScript筆記設計模式
- 好程式設計師web前端培訓分享JavaScript學習筆記之正則程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓分享JavaScript學習筆記之陣列程式設計師Web前端JavaScript筆記陣列
- 好程式設計師web前端培訓分享HTMLCSS學習筆記BFC程式設計師Web前端HTMLCSS筆記
- 好程式設計師web前端培訓分享JavaScript學習筆記Promise程式設計師Web前端JavaScript筆記Promise
- 好程式設計師web前端培訓分享JavaScript學習筆記cookie程式設計師Web前端JavaScript筆記Cookie
- 好程式設計師web前端培訓分享JavaScript學習筆記SASS程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓分享React學習筆記(三)程式設計師Web前端React筆記
- 好程式設計師web前端培訓分享React學習筆記(一)程式設計師Web前端React筆記
- 好程式設計師web前端培訓分享React學習筆記(二)程式設計師Web前端React筆記
- 好程式設計師web前端培訓分享JavaScript學習筆記之ES5程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓分享JavaScript學習筆記之迴圈結構程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓分享學習JavaScript程式設計師Web前端JavaScript
- 好程式設計師web前端培訓分享JavaScript學習筆記分支結構程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓JavaScript學習筆記DOM程式設計師Web前端JavaScript筆記
- 好程式設計師web前端培訓JavaScript學習筆記--jQuery程式設計師Web前端JavaScript筆記jQuery
- 好程式設計師web前端培訓學習筆記Vue學習筆記一程式設計師Web前端筆記Vue
- web前端培訓分享node學習筆記Web前端筆記
- 好程式設計師web前端培訓分享之HTMLCSS學習筆記css3-多列程式設計師Web前端HTMLCSS筆記S3
- 好程式設計師web前端培訓學習筆記Vue學習筆記之二程式設計師Web前端筆記Vue
- 好程式設計師web前端培訓分享JavaScript學習筆記函式進階程式設計師Web前端JavaScript筆記函式
- 好程式設計師web前端培訓分享JavaScript學習指南程式設計師Web前端JavaScript
- 好程式設計師web前端培訓分享之HTMLCSS學習筆記媒體查詢+ rem用法程式設計師Web前端HTMLCSS筆記REM
- 好程式設計師web前端培訓分享HTMLCSS學習之CSS基礎程式設計師Web前端HTMLCSS
- 好程式設計師web前端培訓分享JavaScript學習筆記閉包與繼承程式設計師Web前端JavaScript筆記繼承
- 好程式設計師web前端培訓分享JavaScript學習筆記ajax及ajax封裝程式設計師Web前端JavaScript筆記封裝
- 好程式設計師web前端培訓分享JavaScript學習筆陣列的排序程式設計師Web前端JavaScript陣列排序
- 好程式設計師web前端培訓分享之uni-app學習筆記uni-app詳解程式設計師Web前端APP筆記
- 好程式設計師web前端培訓HTMLCSS學習筆記之頁面最佳化程式設計師Web前端HTMLCSS筆記
- 好程式設計師web前端培訓分享詳解JavaScript學習筆記建構函式程式設計師Web前端JavaScript筆記函式
- 好程式設計師web前端培訓分享HTMLCSS學習筆記css3選擇器程式設計師Web前端HTMLCSS筆記S3
- 好程式設計師web前端培訓分享怎樣學好css?程式設計師Web前端CSS
- 好程式設計師web前端分享Vue學習筆記(一)程式設計師Web前端Vue筆記
- 好程式設計師web前端培訓分享CSS基礎知識學習程式設計師Web前端CSS
- 好程式設計師web前端分享Nodejs學習筆記之Stream模組程式設計師Web前端NodeJS筆記
- 好程式設計師web前端培訓分享JavaScript框架J程式設計師Web前端JavaScript框架
- 好程式設計師web前端教程分享JavaScript學習筆記之Event事件二程式設計師Web前端JavaScript筆記事件