WebAndNodejs
HTML and CSS
-
默认标签解释
<!DOCTYPE html> <!--规定用这个规则--> <html lang="en"> <head> <!--hai de 就是定义你一些内在的东西--> <!--charset \cha sai te--> <meta charset="UTF-8"> <!--mai te 自闭标签--> <!--标签的属性--> <title name="alex">你好</title><!--tai tou 是头部的意思--> </head> <body> <!--bao dei 网页体--> gdfg </body> </html> <!--xxx--> <!--注释-->
HTML head
-
set head
<!--页面编码--> <meta http-equiv="content-type" content="text/html.charest=utf-8"> ####################################### <meta charset="UTF-8"> <!--跳转--> <meta http-equiv="Refresh" Content="5;Url=http://www.autohome.com.cn"/> <!--刷新--> <meta http-equiv="Refresh" Content="30"> <!--关键词--> <meta name="keywords" content="星际老男孩"> <!--X-UA-Compatible,只对ie有用这段代码是然ie用最新的版本来处理它--> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <!--Link引入css--> <link rel="stylesheet" type="text/css" href="css/common.min.css" > <!--Link图标--> <link rel="shortcut icon" href="image/favicon.ico"> <!---->
HTML body
-
标签分为行内标签和块级标签,span,a,select 等,行内标签有多少占多少;div, h1,p 等块级标签 ,没有一行也要占满一行。
-
有一些符号会冲突,随意需要字符码。
-
p表示段落,默认段落之间是有间距的
<p></p>
;dr 是换行符<br />
。 -
a标签
<!--这是html的注释信息--> <!--直接跳转--> <a href="http://www.baidu.com">跳转</a> <!--新建在跳转--> <a href="http://www.baidu.com" target="_blank">跳转</a> -
锚,寻找页面中id相等的标签,将其标签放置再顶部
<a href="#i1">第一章</a> <a href="#i2">第二章</a> <a href="#i3">第三章</a> <!--id不能重复--> <div id="i1" style="height: 500px";>第一章内容</div> <div id="i2" style="height: 500px";>第二章内容</div> <div id="i3" style="height: 500px";>第三章内容</div> -
H标签
<!--h标签只有六个,分别是,以次排序字体大小--> <h1></h1> <h2></h2> <h3></h3> <h4></h4> <h5></h5> <h6></h6> <h6 style="font-size: 65px"></h6> -
标签使用方法
<form><!--fou mu 表单--> <div style="border: 1px solid red;"> <!--样式边框1px纯红色--> <p>用户名<input type="text" /></p> <!--输入文字--> <p>密码<input type="password" /></p> <!--电子邮件--> <p>邮箱<input type="email" /></p> <!--输入类型密码--> <p>性别<br />男<input type="radio" name="gender" /> <!--男输入类型单选名性别--> <br />女<input type="radio" name="gender" checked="checked" /> <!--checked是设置默认选中的--> </p> <!--女输入类型单选名性别--> <p>爱好 <!--1输入类型复选框--> <dr />1<input type="checkbox" checked="checked"/> <!--checked是设置默认选中的--> <dr />2<input type="checkbox" /> <dr />3<input type="checkbox" /> <dr />4<input type="checkbox" /> <dr />5<input type="checkbox" /> </p> <p>城市 <select> <!--选择--> <option>上海</option> <!--选择选项--> <option>武汉</option> <option>甘肃</option> </select> <!--选择多个尺寸10--> <select multiple size="10"> <option>上海</option> <option>武汉</option> <option>甘肃</option> </select> <select> <!--选择组 标签--> <optgroup label="一线"> <option>上海</option> <option>武汉</option> <option>甘肃</option> </select> </p> <!--输入类型文件--> <p>文件 <input type="file"/></p> <p>备注 <textarea></textarea> <!--输入类型提交值提交--> <input type="submit" value="提交" /> <!--输入类型按钮值按钮--> <input type="button" value="按钮" /> <!--输入类型复位值复位--> <input type="reset" value="复位" /> </div> </form> -
checkbox
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="text" placeholder="用户名" /> <!--placeholder是输入框中的提示符> <!--<form action="https://www.sogou.com/web" method="get">--> <!--以get的方法提交--> <!-- <form action="https://www.sogou.com/web" method="post">--> <!--以post的方法提交--> <!--以get的方法提交--> <!--你要上传文件必须在 form 属性中加上enctype="multipart/form-data"--> <!--enctype="multipart/form-data" 编码多部分表单数据--> <form action="https://www.sogou.com/web" method="post" enctype="multipart/form-data"> <!--<!–action里面填写什么http就提交到哪的http–>--> <input type="text" name="query"/> <!--name 是键--> 男<input type="radio" name="gender" value="1"/> <!--男输入类型单选名称性别值1--> 女<input type="radio" name="gender" value="0"/> <!--女输入类型单选名称性别值0--> <p>文件: <!--文件--> <input type="file" name="fafafa" /> </p> <p> <select name="city"> <!--发送的时候不许要有标签--> <option value="1">上海</option> <option selected="selected" value="2">北京</option> <!--selected是默认选中--> <option value="3">广州</option> </select> </p> <p> 备注:<textarea name="extra"></textarea> </p> <input type="submit" value="提交" /> </form> <hr/> <!--横线--> <form> <input type="text"/> <input type="submit" value="提交" /> </form> </body> </html> -
ul and table
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> <!--ul方点--> <li>asldsdjfl</li> <li>asldsd ccl</li> </ul> <ol> <!--ul数字--> <li>asldsdjfl</li> <li>asldsd ccl</li> </ol> <dl> <dt>用于标题</dt> <dd>用于文章</dd> <dd>用于文章</dd> </dl> <table border="1"> <!--边境1--> <!--表格--> <thead> <!--表題--> <tr> <!--代表一行--> <!-- <td>第一列</td> <!–代表一列–>--> <!-- <td>第二列</td>--> <!-- <td>第三列</td>--> <!-- <td>第四列</td>--> <!-- <th>第一列</th> <!–代表一列–>--> <!-- <th>第二列</th> <!–th加粗–>--> <!-- <th>第三列</th>--> <!-- <th>第四列</th>--> <th>第1列</th> <!--代表一列--> <th>第2列</th> <!--th加粗--> <th colspan="2">第3列</th> <!--合并左右單元格--> </tr> </thead> <tbody> <tr> <!--代表一行--> <td>第一列</td> <!--代表一列--> <td>第二列</td> <td>第三列</td> <td>第四列</td> </tr> <tr> <!--代表一行--> <td>第一列</td> <!--代表一列--> <td rowspan="2">第二列</td> <!--合并上下單元格--> <td>第三列</td> <td>第四列</td> </tr> <tr> <!--代表一行--> <td>第一列</td> <!--代表一列--> <td>第三列</td> <td>第四列</td> </tr> </tbody> </table> </body> </html> -
fieldset
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <fieldset> <legend>登录</legend> <p>用户名:<input type="text" /></p> <p>密码:<input type="password" /></p> </fieldset> </div> <h1>人才辈出</h1> <iframe style ="width:100%;height: 2000px;" src="http://autohome.com.cn"></iframe> <img src="a.jpg" alt="图片"></img> <!--alt是在你图片无法查看的时候,在旁边提示他是什么什么图片--> </body> </html>
CSS based
-
css文件可以储存为文件但是优先级最低,写在头部优先级高于文件形式,写在标签中是最高的。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--si dai ao 是当前页面都使用--> <!--在这里写上div以后使用div就可以不用写了--> <!--风格背景色红色白色--> <style> div{ background-color: red; color: white; } </style> </head> <body> <!--风格背景色红色白色--> <div style="background-color: red;color: white;">88</div> <div>116+</div> <div>116+</div> <div>116+</div> <div>116+</div> </body> </html>
-
导入css文件
/* 导入css文件就这么写*/ <link rel="stylesheet" href="filename.css" /> -
简单使用
<html> <head> <meta charset="UTF-8"> <title></title> <style> /*标签选择器*/ /*颜色红色*/ /*找到所有的div使用*/ div{ color:green; } /*id选择器*/ /*字体32像素*/ /*只找到有id="il"使用*/ #il{ font-size: 32px; } /*ke la se class选择器*/ /*找到所有有class="c1"使用*/ .c1{ background-color:red; } </style> </head> <body> <span class="c1">1</span> <div class="c1">2</div> <a class="c1">3</a> <a id="il">jjjj</a> <div>nini</div> <div>nini</div> <div>nini</div> </body> </html>
CSS selector
/*div selector*/ div{ /*Find all divs*/ color:green; /*Font color is green*/ } /*id selector*/ #il{ /*Find id equals il*/ font-size: 32px; /*FontSize32*/ } /*class selector*/ .c1{ /*Find all class equals c1*/ background-color:red; } /*层级选择器*/ .c2 div p .c3{ /*找到class="c2"下div下p下class="c3"来使用*/ dackground-color:rcd; } /*组合选择器*/ .c4,.c5,.c6{ /*找到class="c4"and class="c5" and class="c6"*/ background-color:aqua; } <style> .c1[alex="a"]{ color:red; } </style> <div class="c1" alex="a">1</div> /*做筛选把有c1和a的加上样式*/
CSS style
color:red; /*Fnot color*/ background-color:rgb(1,2,3); /*背景颜色,也可以按照rgb的方式显示颜色*/ background-color:#ffdab9; /*背景颜色,也可以按照rgb的十六进制显示颜色*/ background-color: aqua; /*背景颜色*/ font-size:36px; /*字体大小是以像素做的*/ height:150px; /*定义高度为150像素 ,高度没有百分百怎么个说法*/ width:100%; /*自定义宽度为100%,宽度可以百分百显示,按照父级相对占比*/ background-image:url("image.png") /*按照url里的图片设置为背景图片 重复图片*/ background-repeat:none; /*按照url里的图片设置为背景图片 不重复图片*/ background-position:0px,0px; /*图片坐标*/ border-top-color: red; /*top上、right右、bottom下、left左*/ border-top-style: solid; /*solid 实体,dotted 虚线,dashed 跟虚了*/ border-top-width: 4px; /*设置边线4像素红色实体线*/ display:none; /*隐藏并且不留位置*/ visibility : hidden; /*隐藏但是保留位置*/ display:block; /*将行内标签变成块级标签*/ display:inline; /*将行块级标签变成行内标签*/ display:inline-block; /*他是块级标签也是行内标签*/ cursor:printer; url /*需使用的自定义光标的 URL。请在此列表的末端始终定义一种普通的光标,以防没有由 URL 定义的可用光标。*/ default /*默认光标(通常是一个箭头)*/ auto /*默认。浏览器设置的光标。*/ crosshair /*光标呈现为十字线。*/ pointer /*光标呈现为指示链接的指针(一只手)*/ move /*此光标指示某对象可被移动。*/ e-resize /*此光标指示矩形框的边缘可被向右(东)移动。*/ ne-resize /*此光标指示矩形框的边缘可被向上及向右移动(北/东)。*/ nw-resize /*此光标指示矩形框的边缘可被向上及向左移动(北/西)。*/ n-resize /*此光标指示矩形框的边缘可被向上(北)移动。*/ se-resize /*此光标指示矩形框的边缘可被向下及向右移动(南/东)。*/ sw-resize /*此光标指示矩形框的边缘可被向下及向左移动(南/西)。*/ s-resize /*此光标指示矩形框的边缘可被向下移动(南)。*/ w-resize /*此光标指示矩形框的边缘可被向左移动(西)。*/ text /*此光标指示文本。*/ wait /*此光标指示程序正忙(通常是一只表或沙漏)。*/ help /*此光标指示可用的帮助(通常是一个问号或一个气球)*/ margin:12px; /*外边距 (本身不增加)*/ margin:0 auto; /*居中*/ padding:12px; /*内边距 (本身增加)*/ float:left; /*左飘*/ float:right; /*右飘*/ clear:both; /*如果div没有输入值,又想加上样式,就可以用这个*/ position:absolute; relative /*是设置定位类型为相对定位*/ absolute /*是设置定位类型为绝对定位*/ fixed /*固定在一个位置滚动时也不动*/ opacity:0.5; /*透明度,1是不透明*/ opacity:rgba(0,0,0,0.6); /*可以把颜色和透明度一起设置*/ z-index:9; /*设置优先级,数字可以随便设置只要大于就可以*/ !important; /*不管你的优先级多高,只要见到!important都得先使用他的内容*/ text-align:center; /*让他在文本样式中居中*/ ul li:hover{ /*当鼠标换到标签上时自动执行*/ background-color: blueviolet; } .c2:before{ /*在调用的标签前面打印666*/ content:"666"; } .c2:after{ /*在调用的标签后面打印777*/ content:"777"; } .c1{ /*想要三角形可以用边宽*/ border-top-color: transparent solid 4px; border-right-color: transparent solid 4px border-bottom-color: transparent solid 4px; border-left-color: red solid 4px; } .c1{ color:red; /*字体颜色*/ background-color:rgb(1,2,3); /*背景颜色,也可以按照rgb的方式显示颜色*/ background-color:#ffdab9; /*背景颜色,也可以按照rgb的十六进制显示颜色*/ background-color:red; /*也可以用英文颜色来显示*/ background-color: aqua; /*背景颜色*/ font-size:36px; /*字体大小是以像素做的*/ height:150px; /*定义高度为150像素 ,高度没有百分百怎么个说法*/ width:100%; /*自定义宽度为100%,宽度可以百分百显示,按照父级相对占比*/ } <body> <div class="c1">asdlj</div> <div style="width: 500px;"> <div style="width: 20%;background-color:antiquewhite;float: left">adjs</div> <div style="width: 80%;background-color:palegoldenrod;float: left">adjs</div> </body> [随机图片](https://www.dmoe.cc/random.php)
specification
<html> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>标题栏</title> <style> body{ margin:0; /*它的边宽为0*/ } ul{ margin:0; list-style-type:none; /*不显示小标*/ } ul li{ float:left; /*左飘*/ padding:0 8px 0 8px; /*左边和右边的宽度为8px*/ color: while; /*加上字体颜色为白色*/ cursor:pointer; } ul li:hover{ /*当鼠标移动到li标签上时,自动执行里面的样式*/ background-color: blueviolet; } .pg-header{ height:44px; /*他的大小为44px*/ background-color:#2459a2; /*它的颜色为十六进制的#2459a2*/ line-height:44px; /*lai hai te ,按照44放置里面的内容*/ } .w{ width:980px; /*它的宽度为980px*/ margin:0 auto; /*它的边宽为0*/ background-color:red; /*它的颜色为红色*/ } </style> </head> <body> <div class="pg-header"> <div class="w"> <ul> <li>sadf</li> <li>sadf</li> <li>sadf</li> <li>sadf</li> <li>sadf</li> <li>sadf</li> </ul> </div> </div> <div class="pg-body"></div> <div class="pg-footer"></div> </body> </html>
JavaScript
-
JavaScript编程语言,由浏览器编译并运行
/*头部写上也可以写在下面他就可以写JavaScript代码了*/ <script> var a="123"; /*创建局部变量 var wan*/ a="hello world"; /*创建全局变量*/ function f1(){ /*创建函数*/ var i=123; } alert(123); /*弹出框*/ // 单行注释 /*多行注释*/ </script> <script src="commons.js"></script> //导入JavaScript文件 -
特殊的值null什么都不是、undefined未定义、NaN非数字。
-
对于简单的代码可以在浏览器中的console里面写
DataType
Number
// JavaScript中不区分整数和浮点数值,JavaScript中所有数字均用浮点数值表示。 parselnt() // 将某值转成数字,不成工则NaN parseFloat() // 将某值转成浮点数,不成功则NaN // NaN,非数字。可使用isNaN(num)来判断。 // Infinity,无穷大。可使用isFinite(num)来判断。
Srting
obj.length() //长度 obj.trim() //移除空白 obj.trimleft() //移除右空格 obj.trimright() //移除左空格 obj.charAt(n) //返回字符串中的第N个字符 obj.concat(value,) //拼接 obj.indexOf() //从前往后子序列位置 obj.lastlndexof() //从后往前子序列位置 obj.substring() //根据索引获取子序列 obj.slice() //切片 obj.tolowercase() //大写 obj.touppercase() //小写 obj.split() //分割 obj.search() //从头开始匹配,返回匹配成功的第一个位置(g无效) // 跑马灯实例 <div id=i1 style="background-color:green;color:white">欢迎你的到来</div> <script> //是每一秒钟执行一次f1函数 setlnterval("f1()",1000); //创建函数 funcction f1(){ //js获取某一个标签 id=i1 var tag = document.getElementByld("i1"); //获取标签的内容 var text = tag.innerText; //获取第零位置的值 var a = text.charAt(0); //获取第一项以后的所有值 var sub = text.substring(1,text.length); var new_str = sub + a; //将其赋给标签 tag.innerText = new_str; } </script>
Boolean
-
布尔类型只包含真假,与Python不同的是其首字母小写。
-
== 比较值相等、!= 不等于、=== 比较值和类型相等、!=== 不等于、|| 或、&& 且。
数组
obj.length // 数组的大小 obj.push(ele) // 尾部追加元素 obj.pop() // 尾部获取一个元素 obj.UNshift(ele) // 头部插入元素 obj.splice(start,deletecount,value,...) // 插入,删除或替换数组的元素 obj.splice(n,0,val) // 指定位置插入元素 obj.splice(n,1,val) // 指定位置替换元素 obj.splice(n,1) // 指定位置删除元素 obj.slice() // 切片 obj.reverse() // 反转 obj.join(sep) // 将数组元素链接起来以构建一个字符串 obj.concat(val,...) // 链接数组 obj.sort() // 对数组元素进行排序
Command
Operational data
// 序列化 json.stringify(obj) // 序列化 json.parse(str) // 反序列化 // 转义 encodeURL() // URL中的转义字符 decodeURL() // URL中未转义的字符 encodeURLComponent() // 转义URL组件中的字符串(全部) decodeURLCompoent() // URL组件中的未转义字符 escape() // 对字符串转义 unescape() // 给转义字符串解码 URLError() // 由URL的编码和解码方法抛出 // eval,JavaScript中的eval是Python中eval和exec的合集,即可以编译也可以获取返回值。 eval() EvalError // 执行字符串中的JavaScript代码 // 时间处理 d = new Date() // 获取当前时间 d.getfullyear() // 获取年份 d.gethours() // 获取小时 d.setminutes(45) // 修改秒
语句和异常
-
条件语句
if(条件){ } else if (条件){ } else { } switch(name){ //name等于谁就执行谁 case "1": age = 123; break case "2": age = 456; break default: age = 777; } -
循环语句
var names = {"alex","tony","rain"}; //i是一个变量,nmaes.length是长度,i++是自加 for(var i=0;i<nmaes.length;i++){ pass } //这个for循环,循环的是索引的值 for (var item in li){ console.log(item,li[item]); } while(条件){} -
异常处理
try { //这段代码从上往下执行,其中任何一个语句抛出异常该代码块就结束执行 } catch (e){ //如果try代码块中抛出了异常,catch代码块中的代码就会被执行。 //额是一个局部变量,用来指向error对象或者其他抛出的对象 } finally{ //无论try中代码是否抛出异常都会执行finally里面的命令 } //主动抛出异常 Python raise Exception (xxx) JavaScript throw new Error("asdfasdf") -
函数
//普通函数 function func(arg){ return true; } //匿名函数 var func = function(arg){ return "tony"; } //自执行函数 (function(arg){ console.log(arg); })("123")
作用域的操作
-
JavaScript中无块级作用域
function Main{ if (1==1){ var name = "seven0"; } console.log(name); } -
JavaScript采用函数作用域
function Main{ var innerValue = "seven"; } Main(); console.log(innerValue); -
javaScript的作用域链
xo = "alex"; function Func(){ var xo = "liang"; function inner(){ var xo = "asdf"; console.log(xo); } inner(); } Func(); -
javaScrip的作用域链执行前已创建
xo = "alex"; function Func(){ var xo = "liang"; function inner(){ console.log(xo); } return inner; } var ret = Func(); ret();
面向对象
function Foo (name,age){ this.Name = name; this.Age = age; this.Func = function(arg){ return this.Name +arg; } } var obj = new Foo("alex",18); //想要创建对象必须加上new var ret = obj.Func("sb"); console.log(ret)
DOM
Find Elements
-
直接查找
document.getElementById // 根据ID获取一个标签 document.getElementsByName // 根据name属性获取标签集合 document.getElementsByClassName // 根据class属性获取标签集合 document.getElementsByTagName // 根据标签签名获取标签集合 -
间接查找
// 既包含元素有包含文本内容 parentNode // 父节点 childNodes // 所有子节点 firstChild // 第一个子节点 lastChild // 最后一个子节点 nextSibling // 下一个兄弟节点 previousSibling // 上一个兄弟节点 // 只包含元素 parentElement // 父节点标签元素 children // 所有子标签 firstElementChild // 第一个子标签元素 lastElementChild // 最后一个子标签元素 nextElementtSidling // 下一个兄弟标签元素 previousElementSibling // 上一个兄弟标签元素
Operate
-
内容
immerText // 获取标签文本 outerText innerHTML // HTML内容 value // 获取值 onfocus="focuns();" // 获取焦点,执行函数 onblur="Blur();" // 失去焦点,执行函数 onclick="Modal();" // 点击后执行函数 attributes // 获取所有标签属性 setAttribute(key,value) // 设置标签属性 getAttribute(key) // 获取指定标签属性 t.removeAttribute() // 移除指定的值 className // 获取所有类 classList.remove(cls) // 删除指定类 classLIst.add(cls) // 添加类 tag.style.font-size = 40px // 修改样式 // ****************** 创建标签 ****************** // 方式1对象方式 var tag = document.createElement("a") // 创建标签 tag.innerText = "wupeiqi" // 添加内容 tag.className = "c1" // 添加类 tag.href = "http://www.baidu.com" // 添加链接 //方式2字符串方式 var tag = '<a class = "c1" href = "http://www.cnblogs.com">wupeiqi</a>' // ****************** 操作标签 ****************** // 方式1 var obj = "<input type = 'text' />"; xxx.insertAdjacentHTML("beforeEnd",obj); // xxx.insertAdjacentText("beforeEnd",obj); // 把标签当做文本显示 // 注意:第一个参数只能是“beforeBegin”是放到内部的上面“afterBegin”外部的最上面,beforeEnd内部的最下面“afterEnd”外部的最下面 // 方式2 var tag = document.createElement("a") xxx.appendChild(tag) xxx.insertBefore(tag,xxx[1]) this // 当前触发事件标签 createElement appendChild // ****************** 定时器 ******************* setInterval // 多次定时器 clearInterval // 清除多次定时器 setTimeoutsetTimeout(function(){},5000); // 单次定时器 clearTimeout // 清除单次定时器 // ****************** 高度 ********************* clientHeight // 可见区域 height + padding clientTop // border高度 offsetHeight // 可见区域:height+ padding+ border offsetTop // 上级定位标签高度 scrollHeight // 全文高:height+ padding // 特别的:document.documentElement代指文档根节点 document.body.scrollTop = 0 // 页面上自带的滚动条获取滚动条位置 // ****************** 其他 ********************** comsole.log() // 输出框 alert() // 弹出框 confirm() // 确定框 // ****************** URL和刷新 ****************** location.href // 获取URL location.href = "url" // 重定向 location.reload() // 重新加载 -
事件
onabort // 图像的加载别中断。 onblur // 元素失去焦点。 onchange // 域的内容被改变。 onclick // 当用户点击某个对象时调用的事件句柄。 ondblclick // 当用户双击某个对象时调用的事件句柄。 onerror // 在加载文档或图像是发生错误。 onfocus // 元素获取焦点。 onkeydown // 某个键盘按键被按下。 onkeypress // 某个键盘按键被按下并松开。 onkeyup // 某个键盘按键被松开。 onload // 一张页面或图像完成加载。 onmousedown // 鼠标按钮被按下。 onmousemove // 鼠标被移动。 onmouseout // 鼠标从某元素移开。 onmouseover // 鼠标移到某元素之上。 onmouseup // 鼠标按键被松开。 onreset // 重置按钮被点击。 onresize // 窗口或框架被重新调整大小。 onselect // 文本被选中。 onsubmit // 确定按钮被点击 onunload // 用户退出页面 -
搜索框
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鸟教程(runoob.com)</title> </head> <body> <input ID ="v1" type="text" value="请输入关键字" onfocus="Focus();" onblur="Blur();"/> <Script> function Focus(){ var tag = document.getElementById("v1"); if(tag.value == "请输入关键字"){ tag.value = "" } } function Blur(){ var tag = document.getElementById("v1"); var val = tag.value; if(val.trim().length == 0){ tag.value = "请输入关键字" } } </Script> </body> </html> -
小例子
<style> .hide{ display:none !important; } .shade{ position:fixed; top:0; bottom:0; left:0; right:0; background-color:rgba(0,0,0,.6); z-index:1000; } .modal{ height:200px; width:400px; background-color:white; position:fixed; top:50%; left:50%; margin-left:-200px; margin-top: -100px; z-index:1001; } </style> <boody> <div style="height:2000px;backgrownd-color:#dddddd;"> <input type="button" value="点我" onclick="ShowModal();"> <div> <div id ="shade" class="shade hide"></div> <div id = "modal" class="modal hide"> /*javascript:void(0);什么也不做*/ <a href="javascript:void(0);" onclick="HideModal();">取消</a> </div> <script> function ShowModal(){ var t1 = document.getElementById("shade") var t2 = document.getElementById("shade") t1.classList.remove("hide") t2.classList.remove("hide") } function HideModal(){ var t1 = document.getElementById("shade") var t2 = document.getElementById("shade") t1.classList.add("hide") t2.classList.add("hide") } </script> </boody> -
全选,取消,反选
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鸟教程(runoob.com)</title> </head> <body> <input type="button" value="全选" onclick = "CheckAll();" /> <input type="button" value="取消" onclick = "ReverseAll();" /> <input type="button" value="反选" onclick = "c();"/> <table border="1" > <tbody id = "ba"> <tr> <td><input type="checkbox" /></td> <td>第二列</td> <td>第三列</td> </tr> <tr> <td><input type="checkbox" /></td> <td>第二列</td> <td>第三列</td> </tr> <tr> <td><input type="checkbox" /></td> <td>第二列</td> <td>第三列</td> </tr> </tbody> </table> <Script> function CheckAll(){ var tb = document.getElementById("ba") var trs = tb.children; for (var i=0;i<trs.length;i++){ var current_tr = trs[i]; var ck = current_tr.firstElementChild.firstElementChild ck.checked = true } } function ReverseAll(){ var tb = document.getElementById("ba") var trs = tb.children; for (var i=0;i<trs.length;i++){ var current_tr = trs[i]; var ck = current_tr.firstElementChild.firstElementChild ck.checked = false } } function c(){ var tb = document.getElementById("ba") var trs = tb.children; for (var i=0;i<trs.length;i++){ var current_tr = trs[i]; var ck = current_tr.firstElementChild.firstElementChild if (ck.checked){ ck.checked = false } else{ ck.checked = true } } } </Script> </body> </html> -
点赞
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .item{ padding:50px; position:relative; } </style> </head> <body> <div class="item"> <a onclick="Favor(this)";>赞</a> <!--this 是当前触发事件的标签--> </div> <div class="item"> <a onclick="Favor(this)";>赞</a> </div> <div class="item"> <a onclick="Favor(this)";>赞</a> </div> <script> function Favor(ths){ var top = 49; var left = 71; var op = 1; var fontSize = 18; var tag = document.createElement("span"); tag.innerText = "+1"; tag.style.color="red"; tag.style.position = "absolute"; tag.style.top=top + "px"; tag.style.left = left +"px"; tag.style.opacity = op; tag.style.fontSize = fontSize + "px"; ths.parentElement.appendChild(tag); var interval = setInterval(function(){ top -= 10; left += 10; fontSize += 5; op -= 0.1; tag.style.color="red"; tag.style.top=top + "px"; tag.style.left = left +"px"; tag.style.opacity = op; tag.style.fontSize = fontSize + "px"; if(op <=0.1){ clearInterval(interval); ths.parentElement.removeChild(tag); } },50); } </script> </body> </html> -
定时器的使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> </style> </head> <body> <div id="status" style="color:red;"></div> <input type="submit"onclick="DeleteStatus();"value="删除" /> <script> function DeleteStatus(){ var s = document.getElementById("status"); s.innerText = "删除成功"; setTimeout(function(){ s.innerText = ""; },5000); } </script> </body> </html> -
回到顶点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> </style> .back{ position:fixed; right:20px; bottom:20px; color:red; } .hide{ display:none; } </head> <body> <div style="height:2000px;background-color:#dddddd;"></div> <div id="back" class="back hide" onclick="BackTop();">返回顶部</div> <script> function BackTop(){ document.body.scrollTop = 0; } function BodyScroll(){ var s= document.body.scrollTop; var t = document.getElementById("back"); if (s>=100){ t.classlist.remove("hide"); } else{ t.classlist.add("hide"); } } </script> </body> </html> -
提交表单
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form id="f1"> <input type="text"/> <input type="submit" value="提交"/> <a onclick="Submit()">提交</a> </form> <script> function Submit(){ var form = document.getElementById("f1"); form.submit(); } </script> </body> </html> -
监听键盘
<style> .hide{ display:none !important; } .shade{ position:fixed; top:0; bottom:0; left:0; right:0; background-color:rgba(0,0,0,.6); z-index:1000; } .modal{ height:200px; width:400px; background-color:white; position:fixed; top:50%; left:50%; margin-left:-200px; margin-top: -100px; z-index:1001; } </style> <boody> <div style="height:2000px;backgrownd-color:#dddddd;"> <input type="button" value="点我" onclick="ShowModal();"> <div> <div id ="shade" class="shade hide"></div> <div id = "modal" class="modal hide"> /*javascript:void(0);什么也不做*/ <a href="javascript:void(0);" onclick="HideModal();">取消</a> </div> <script> function ShowModal(){ var t1 = document.getElementById("shade") var t2 = document.getElementById("shade") t1.classList.remove("hide") t2.classList.remove("hide") } function HideModal(){ var t1 = document.getElementById("shade") var t2 = document.getElementById("shade") t1.classList.add("hide") t2.classList.add("hide") } window.onkeydown = function(event){ comsole.log(event); if(event.keyCode == 27){ HideModal(); } } </script> </boody> -
用户验证
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="http://www.baidu.com"> <input type="text" id="username"/> <input type="submit" value="提交"onclik="return SubmitForm();"> </form> <script> function SubmitForm(){ var user = documcnt.getElementById("username"); if(user.value.length>0){ return true; } else{ alert("用户名输入不能为空") return false; } } </script> </body> </html>
JQuery
<script src="jquery-1.12.4.js"></script> // 引入文件 $(ths) // 转换为jquery对象 $(ths)[0] // jquery对象转换为dom
Find
Selector
-
#
代表id选择器,标签名代表标签选择器,.
代表class类选择器,*
代表所有。 -
#i1,#i2,#i3
是组合,#i1 .c1
按层级找i1的子子孙孙,#i1>.c1
在儿子里面找$(this).hide() // 隐藏当前元素 $("p").hide() // 隐藏所有 <p> 元素 $("p.test").hide() // 隐藏所有 class="test" 的 <p> 元素 $("#test").hide() // 隐藏 id="test" 的元素 $("input:eq(1)") // **********************筛选****************************** :first // 获取匹配的第一个元素 :not(selectos) // 不是内个 :even // 偶数 :odd // 奇数 :eq(index) // 第几个索引 :gt(index) // 大于 :lt(index) // 小于 $("input:eq(1)") // **********************属性****************************** [attribute] [attribute=value] [attribute!=value] [attribute^=value] [attribute$=value] [attribute*=value] [attrSei1][attrSei2][attrSei3] $("[attribute]") // **********************表单****************************** :input :text :password :radio // **********************表单对象属性************************ :enabled // 所有可以操作 :disabled // 所有不可以操作 :checked // 选中 :selected // 选中 -
小例子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="i1"> <div class="item"></div> <div class="item"> <div class="c1"></div> <a>百度</a> </div> <div class="item"></div> </div> <script src="jquery-1.12.0.js"> <script> removeClass </script> </body> </html>
筛选器
eq(1) // 索引这里的都是方法 first() // 第一个 last() // 最后一个 hasClass(class) // 是否有某个样式 filter() // 某个里面筛选 is() // 判断返回的是不是指定的标签 map() has() // **********************查找************************ children() // 所有的孩子 find() // 所有的子子孙孙 parent() // 父亲的 parentAll() // 父亲所有 parentUnti() // 父亲一个的父亲一个知道找到 next() // 下一个 nextAll() // 下边所有 nextUnti() // 下一个的下一个知道找到 pcev() // 上一个 pcevAll() // 上边所有 pcevUnti() // 上一个的上一个知道找到 siblings() // 找兄弟
-
菜单
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> </boody> </html> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .hide{ display:none; } .menu{ width:200px; height:600px; border:1px solid #dddddd; overflow:auto; } .menu .item .title{ height: 40px; line-height:40px; background-color:#2459a2; color:white; } </style> </head> <body> <div class="menu" > <div class="item"> <div class="title" onclick="ShowMenu(this);">菜单一</div> <div class="body"> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> </div> </div> <div class="item"> <div class="title" onclick="ShowMenu(this)";>菜单二</div> <div class="body hide"> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> </div> </div> <div class="item"> <div class="title" onclick="ShowMenu(this)";>菜单三</div> <div class="body hide"> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> </div> </div> </div> <script src="jquery-3.6.0.min.js"></script> <script> function ShowMenu(ths){ $(ths).next().removeClass("hide") ; $(ths).parent().siblings().find(".body").addClass("hide"); } </script> </boody> </html>
JQuery CSS
// ************************属性***************************** attr() // 设置属性 removeAttr() // 删除属性 prop() // 写一个参数是获取值,写两个是赋值 removeProp() // 删除 // ************************css类***************************** addClass() // 添加样式 removeClass() // 删除样式 toggleClass() // 单击一次添加,再点击一下删除 // ************************HTML代码/文本/值***************************** HTML() // 没有参数是获取内容,有参数是赋值,下面的都一样 TEXT() VAL() // ************************css***************************** css() // 一个参数是获取,两个是赋值 // ************************位置***************************** offset() // 获取标签的高度,宽度 position() // 获取当前标签与父标签的距离 scrollTop() // 与顶部的距离 scrollLeft() // 与右边的距离 // ************************尺寸***************************** height() // 高度 width() // 宽度 innerHeight() // 包括边距不带边宽 innerWdth() outerHeight() // 包括边距带边宽 outerWdth()
-
全选,反选,取消(jquery版)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鸟教程(runoob.com)</title> </head> <body> <input type="button" value="全选" onclick = "CheckAll();" /> <input type="button" value="取消" onclick = "ReverseAll();" /> <input type="button" value="反选" onclick = "c();"/> <table border="1" > <tbody id = "ba"> <tr> <td><input type="checkbox" /></td> <td>第二列</td> <td>第三列</td> </tr> <tr> <td><input type="checkbox" /></td> <td>第二列</td> <td>第三列</td> </tr> <tr> <td><input type="checkbox" /></td> <td>第二列</td> <td>第三列</td> </tr> </tbody> </table> <script src="jquery-3.6.0.min.js"><script> <Script> function CheckAll(){ $("#tb input[type="checkbox"]").prop("checked",true); } function ReverseAll(){ $("#tb input[type="checkbox"]").prop("checked",false); } function c(){ $("#tb input[type="checkbox"]").each(function(i)){ if($(this).prop("checked")){ $(this).prop("checked",false); } else{ $(this).prop("checked",true); } }); } </Script> </body> </html>
文档处理
// ************************内部插入************************** append() 最后边添加 appendTo() 把什么翻到什么里面 prepend() 子元素的最前边 prependTo() // ************************外部插入************************** after() 当前标签的后边 before() 当前标签的前边 insertAfter() 把什么放到什么后边 insertBefore() // ************************删除***************************** empty() 清空所提供标签的内部 remove() 清除所有提供的标签 // ************************复制***************************** clone 复制 // ************************示例***************************** <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div> <a> <a onclick="Add(this);">+</a> <input type="text" /> </a> </div> <script src=""></script> <script> function Add(ths){ var p= $(ths).parent().clone(); p.find("a").text("-"); p.find("a").attr("onclick","Remove(this)") $(ths).parent().parent().append(p); } function Remove(ths){ $(ths).parent().remove(); } </script> </boody> </html>
事件
-
jquery菜单
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> </boody> </html> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .hide{ display:none; } .menu{ width:200px; height:600px; border:1px solid #dddddd; overflow:auto; } .menu .item .title{ height: 40px; line-height:40px; background-color:#2459a2; color:white; } </style> </head> <body> <div class="menu" > <div class="item"> <div class="title"">菜单一</div> <div class="body"> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> </div> </div> <div class="item"> <div class="title" ;>菜单二</div> <div class="body hide"> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> </div> </div> <div class="item"> <div class="title";>菜单三</div> <div class="body hide"> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> <p>内容一</p> </div> </div> </div> <script src="jquery-3.6.0.min.js"></script> <script> $(".item .title").click(function(){ //这里的this就是被点击的标签 $(this).next().removeClass("hide") ; $(this).parent().siblings().find(".body").addClass("hide"); }) </script> </boody> </html> //绑定事件 $(".item .title").bind("click",function(){ //这里的this就是被点击的标签 $(this).next().removeClass("hide") ; $(this).parent().siblings().find(".body").addClass("hide"); }) //当文档数加载完毕后,自动执行 $(function(){}) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="text" onclick="Add();" /> <ul> <li>123</li> <ul> <script src="xxx"></script> <script> $(function(){ $("li").click(function(){ alert($(this).text()); //先找到ul在找到li,在给li绑定事件,叫做延迟加载 $("ul").delegate("li","click",function(){ alert($(this).text()); }) function Add(){ var tag = document.createElement("li"); tag.innerText = "666"; $("ul").append(tag); } </script> </boody> </html> -
jquery的循环
each(function(i){ each是循环中间是函数,i是索引的第0 ,第1个,第2个自动给你加上 this是当前正在循环的元素 $(this)当前标签的jquery对象 });
jQuery示例
-
表单验证,jQuery扩展
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .item{ width:250px; height:60px; position:relative; } .item input{ width:200px; } .item span{ position:absolute; top:20px; left:20px; font-size:8px; background-color:indianred; color:while; display:inline-block; width:200px; } </style> </head> <body> <div> <form> <div class="item"> <input class="c1" type="text" name="username" label="用户名" /> </div> <div class="item"> <input class="c1" type="password" name="pwd" label="密码"> </div> <input type="submit"value="提交" onclick="CheckValid();"/> </form> </div> <script> function CheckValid(){ $("form.item span").remove(); var flag = true; $("form .c1").each(function(){ var val = $(this).attr("label"); var tag = document.createElement("span"); tag.innerText = label+"不能为空"; $(this).after(tag); flag = false; }) return flag; } </script> </body> </html> -
jquery版本的绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .item{ width:250px; height:60px; position:relative; } .item input{ width:200px; } .item span{ position:absolute; top:20px; left:20px; font-size:8px; background-color:indianred; color:while; display:inline-block; width:200px; } </style> </head> <body> <div> <form> <div class="item"> <input class="c1" type="text" name="username" label="用户名" /> </div> <div class="item"> <input class="c1" type="password" name="pwd" label="密码"> </div> <input type="submit"value="提交" onclick="CheckValid();"/> </form> </div> <script> function BindCheckValid(){ $("form :submit").click(function(){ var flag = true; $("form.item span").remove(); $("form .c1").each(function(){ var val = $(this).val(); if(val.length<=0){ var label = $(this).attr("label"); var tag = document.createElement("span"); tag.innerText = label + "不能为空"; $(this).after(tag); flag = false; } }) return flag; }); } </script> </body> </html> -
jquery的for循环
function f1(){ $.each([11,22,33,44],function(k,v){ if(k==2){ //这里的k是索引的数v是值 return; //这里的return只会返回里面的函数,就和Python中的继续一样,如果你想停止循环可以用“return false” } }) } -
jquery扩展方法
jquery.fn.extend(object) $.extend({ "dalong":function(arg){ console.log(arg); } }); $("form").dalong("1234") 必须是用标签,这个里面有一个this代指这个标签 jquery.extend(object) 给jquery添加函数永久存在 $.extend({ "dalong":function(arg){ console.log(arg); } }); $.dalong("1234") -
文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .item{ width:250px; height:60px; position:relative; } .item input{ width:200px; } .item span{ position:absolute; top:20px; left:20px; font-size:8px; background-color:indianred; color:while; display:inline-block; width:200px; } </style> </head> <body> <div> <form> <div class="item"> <input class="c1" type="text" name="username" label="用户名" require="true" min-len="6" /> </div> <div class="item"> <input class="c1" type="password" name="pwd" label="密码" require="true" phone="true"> </div> <input type="submit"value="提交" onclick="CheckValid();"/> </form> </div> <script src="jquery-xxx.js"</script> <script> $(function(){ $.valid("#form1"); }) </script> </body> </html> -
文件jquery1
(function(iq){ jq.extend({ valid:function(form){ jq(form).find(":submit").click(function(){ jq(form).find(".item span").remove(); var flag = true; jq(form).find(":text,:password").each(function(){ var require = $(this).attr("tequire"); if (require){ var val = $(this).val(); if (val.length<=0){ var lavel = $(this).attr("label"); ErrorMessage($(this),label + "不能为空"); flag= false; return false; } var minLen = $(this).attr("min-len");\ if (minLen){ var minLenInt = parseInt(minLen); if(val.lenth<minLenInt){ var label = $(this).attr("label"); ErrorMessage($(this),label + "长度最小为"+minLen); flag = false; return false; } } } } var phone = $(this).attr("phone"); if(phone){ var phoneReg = /^[3|5|8]\d{9}$/; if(!phoneReg.test(val)){ var lavel = $(this).attr("label"); ErrorMessage($(this),label + "格式错误"); flag = false; return false; } } }) return flag; } }) } )} })(jQuery);
Js的正则表达式
定义正则表达式 /.../ 用于定义正则表达式 /.../g 表示全局匹配 /.../i 表示不区分大小写 /.../m 表示多行匹配 js正则匹配时本身就是支持多行,此处行匹配只是影响正则表达式^$来匹配换行的内容 var pattern = /^Java\w*/gm; var text = "JavaScript is more fun than \nJavaEE or JavaBeans!"; result = pattern.exec(text) result = pattern.exec(text) 匹配 JavaScript中支持正则表达式,其主要提供了连个功能: text(string) 检查字符串中是否和正则匹配 exec(string) 获取正则表达式匹配的内容,如果未匹配,值为null,否则,获取匹配成功的数组。 字符串中相关方法 obj.search(regexp) 获取索引位置,搜索整个字符串,返回匹配成功的第一个位置(g模式无效) obj.match(regexp) 获取匹配内容,搜索整个字符串,获取找到第一个匹配内容,如果正则是g模式找到全部 obj.replace(regexp,replacement) 替换匹配替换,正则中有g则替换所有,否则只替换第一个匹配项, $数字:匹配的第n个组内容; $&: 当前匹配的内容; $`:位于匹配子串左侧的文本; $':位于匹配子串右侧的文本 $$:直接量$符号
非全局模式 获取匹配结果数组,注意:第一个元素是第一个匹配的结果,后面元素使正则子匹配(正则内容分组匹配) var pattern = /\bJava\w*\b/; var text = "JavaScript is more fun than Java or JavaBeans!"; result = pattern.exec(text) var pattern = /\b(Java)\w*\b/; var text = "JavaScript is more fun than Java or JavaBeans!"; result = pattern.exec(text) 全局模式 需要反复调用exec方法,来一个一个获取结果,直到匹配获取结果为null表示获取完毕 var pattern = /\bJava\w*\b/g; var text = "JavaScript is more fun than Java or JavaBeans!"; result = pattern.exec(text) var pattern = /\b(Java)\w*\b/g; var text = "JavaScript is more fun than Java or JavaBeans!" result = pattern.exec(text)
Nodejs
-
node.js主讲人:kerwin。基于最新v16.13版本学习。
-
node.js是通过js可以编写、服务端开发、底层平台和周边生态。只要你会js就可以学node.js,我们就要学习node.js基础、Koa2、MySQL、全站项目、即时通讯和测试框架 。
-
学习完成后可以使用node.js写Restful Api接口、动态web网页开发、测试框架。
基础
认识
-
node.js是一个JavaScript运行环境。它让javascript可以开发后端程序,实现几乎其他后端语言实现的所有功能,可以与PHP、JAVA、Python等后端语言平起平坐。
-
node.js是基于v8引擎是Google发布的开源javaScript引擎,本身就是用于Chrome浏览器的js解释部分,但是Ryan Dahl吧 这个v8搬到了服务器上,用于做服务器的软件。
-
node.js的特性
-
node.js语法全是js语法,只要你懂js基础就可以学习node.js后端开发。
-
-
开发周期短、开发成本低、学习成本低。
-
-
-
浏览器环境与node环境
-
浏览器的环境是硬件、中间层上分为了blink、HTML/css和v8、javascript。而node是硬件、中间层、v8、javascript将blink给去了。
-
node.js可以解析js代码(没有浏览器安全级别的限制)提供跟多系统级别的api。
-
-
环境搭建
-
去官网下载nodejs软件
https://www.nodejs.org/en/
,下载LTS的稳定版即可。下载后需要右键软件点击属性,查看属性中是否有‘软件在系统中受限,是否同意解除受限’,勾选即可。安装后打开cmd中查看一下版本node --version
。
-
模块
-
js中模块化开发是有问题的,如果你引入多个文件后,如果多个文件中有相同的函数名就会被覆盖,导致出现文件。
-
在js中模块化编程的时候需要指定一个接口文件来解决依赖关系的问题。所以需要CommonJS规范
-
我们可以把公共的功能抽离成为一个单独的js文件,作为一个模块,默认情况下面这个模块里面的方法或者属性,外面是无法访问的。如果想让外面的模块访问需要在模块里面通过exports或者module.exports暴露属性或者方法。
// a.js const name = 'aasd' const sayName = () => { console.log(name) } // 接口暴露方法1 module.exports = { say:sayName } // 接口暴露方法2 exports.say = sayName // 错误 exports = { say:sayName } // b.js const m1 = require('./a') m1.say()
install
-
Npm&Yarn,模块下载工具
npm init // 包信息记录 npm install <module> -g (uninstall,update) // 下载模块 npm install <module> --save-dev (uninstall,update) // 版本锁定 npm list -g (不加-g,列举当前目录下的安装包) npm info <module> npm info <module> version(get Latest version) npm install md5@1 (select version install) npm outdated(检查包是否已经过时) "2.1.0" // 指定版本2.1.0不变 "^2.1.0" // 表示锁定大版本不变2.*.*,只能下载2点几的 "~2.1.0" // 表示锁定前两个号2.1.*,只能下载2.1.*的版本 "*" // 表示下载最新的版本 -
全局安装nrm
NRM(npm registry manager)是npm的镜像源管理工具,有时候国外资源太慢,使用这个就可以快速地在npm源间切换 npm config set registry registry.npm.taobao.org // 切换源 npm install -g nrm // install nrm nrm ls // use nrm, 查看可选的源,带*的是当前使用的源,上面的输出表明当前源是官方源。 nrm use taobao // 切换源 nrm test // 速度测试,测试源的响应时间。 npm install -g cnpm --registry=registry.npmmirror.com // 这是一个万丈npmjs.org镜像,你可以用此替代官方版本,同步频率目前为10分钟一次以保证尽量与官方服务同步。 -
yarn
npm install -g yarn 运行超快:yarn缓存了每个下载过的包,所以再次使用时无需重复下载。同时利用并行下载以最大化资源利用率,因此安装速度很快。 超级安全:在执行代码之前,yarn会通过算法校验每个安装包的完整性。 yarn init // 生成package文件 // 添加 yarn add <package> yarn add <package>@<version> yarn add <package> --dev yarn upgrade <package>@<version> // 升级依赖包 yarn remove <package> // 移除依赖包 yarn install // 安装项目的全部依赖 -
ES模块化写法
// /a/a.js const moduleA = { } export default moduleA // /a/b.js const moduleB = { } export{ moduleB } // main.js import moduleA from './a/a.js' import {moduleB} from './a/b.js' console.log(moduleA.getName()) // package.json { "name": "001", "version": "1.1.1", "description": "", "main": "helloworld.js", "type":"module", // 需要将类型改为module才可以使用 "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
内置模块
http模块
-
基本使用
// mian.js var http = require("http") // 导入http模块 var url = require("url") var urls = require("./urls") var views = require("./views") http.createServer((req,res)=>{ // req 接受浏览器传的参数,res 返回渲染的内容 res.writeHead(urls.renderStatus(url.parse(req.url).pathname), // url.parse是用于分析url,.pathname是url的路径 {"Content-Type":"text/html;charset=utf-8"}) // 编写请求头, 设置网页返回类型,和编码格式。 res.write("hello world!") // 返回字符串 res.write(` // 默认是可以返回html到页面的,但是你返回html到页面的时候最好把类型也改一下。 <html> <b>大家好</b> </html> `) res.write(views.url(req.url)) res.end() //res.end([1,2,3]) // 结束通讯并返回数组 }).listen(3000,()=>{ // 设置端口为3000,并设置一个自调函数 console.log("Server Start") // 返回信息到终端 }) // urls.js function renderStatus(url){ var arr = ["/home","/list"] return arr.includes(url)?200:404 } module.exports = { renderStatus } // views.js function url(url){ if (url == "/home"){ return views.Home() }else{ return "404" } } function Home(){ return "hello world!1" } module.exports = { url } // 终端中启动server node main.js // 启动服务器,但是每次修改后都需要重新启动 npm i -g nodemon // 全局安装nodemon模块,也可以安装node-dev模块,两个一样 nodemon main.js // nodemon模块用于帮我们避免每次修改后重新启动。 -
JSONP
-
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,客户端和服务器无法沟通,而 HTML 的
<script>
元素是一个例外。利用<script>
元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。// Server.js var http = require("http") var url = require("url") http.createServer((req,res)=>{ var urlobj = url.parse(req.url,true) switch(urlobj.pathname){ case '/api/aaa': res.end(`${urlobj.query.callback}(${JSON.stringify({ name:"aaa", age:100 })})`) // ${}代表动态获取,JSON.stringify是将一个字典转换为一个json对象。 break; default: res.end("404") } }).listen(3000,()=>{ console.log("Server Start") }) // index.html <!DOCTYPE html> <html lang='en'> <head> <meta charset="utf-8"> <title></title> </htad> <body></body> <script> var oscript = document.createElement("script") oscript.src="http://localhost:3000/api/aaa?callback=test" function test(obj){ console.log(boj) } <script> </html>
-
-
同源策略
-
在服务器和客户端通信时,如果页面和访问的网址地址、端口不同就会被同源策略所拦截。
-
我们要学习如何解除同源策略,应为如果是开放的api就需要所有人都可以访问。
// Server.js var http = require("http") var url = require("url") http.createServer((req,res)=>{ res.writeHead(200,{ "Content-Type":"application/json;charset=utf-8", "access-control-allow-origin":"*" // 用于写入允许的网站访问,*代表全部。 }) var urlobj = url.parse(req.url,true) switch(urlobj.pathname){ case '/api/aaa': res.end(`${JSON.stringify({ name:"aaa", age:100 })}`) // ${}代表动态获取,JSON.stringify是将一个字典转换为一个json对象。 break; default: res.end("404") } }).listen(3000,()=>{ console.log("Server Start") }) // index.html <!DOCTYPE html> <html lang='en'> <head> <meta charset="utf-8"> <title></title> </htad> <body> <script> fetch('http://localhost:3000/api/aaa') // 发送请求 .then(res=>res.json()) // 设置json解析 .then(res=>{ // 访问成功后将结果打印出来 console.log(res) }) </script> </body> </html>
-
-
get请求和post请求
// Server.js var http = require("http") var https = require("https") var url = require("url") http.createServer((req,res)=>{ res.writeHead(200,{ "Content-Type":"application/json;charset=utf-8", "access-control-allow-origin":"*" // 用于写入允许的网站访问,*代表全部。 }) var urlobj = url.parse(req.url,true) switch(urlobj.pathname){ case '/api/aaa': httpget((data)=>{ res.end(data) // 接收回调函数的数据返回给前端 }) break; case '/api/bbb': httppost((data)=>{ res.end(data) // 接收回调函数的数据返回给前端 }) break; default: res.end("404") } }).listen(3000,()=>{ console.log("Server Start") }) function httpget(cb){ var data = "" https.get('https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E5%8C%97%E4%BA%AC%&ci=1&channelId=4',(res)=>{ // 发送get请求给猫眼,猫眼给我们数据 res.on("data",(chunk)=>{ // 以数据流的形式接收数据 data += chunk }) res.on("end",()=>{ // 数据接收完之后,会自动会自行的 cb(data) // 通过回调函数将数据送出去 }) }) } function httppost(cb){ var data = '' var options = { // 编写请求头 hostname:"m.xiaomiyoupin.com", port:'443', path:'/mtop/market/search/placeHolder', method:'POST', headers:{ "Content-Type":"application/json" // 'Content-Type':'x-www-form-urlencoded' // 设置返回类型为这个,他的是表单的数据格式a=3&b=2这种的。 } } var req = https.request(options,(res)=>{ res.on("data",chunk=>{ // 接收 data+=chunk }) res.on("end",()=>{ // 接收完毕 cb(data) }) }) // req.write("name=li&age=12") // 编写请求体中需要携带的数据 req.write(JSON.stringify([{},{"baseParam":{"ypClient":1}}])) req.end() // 发出 } // index.html <!DOCTYPE html> <html lang='en'> <head> <meta charset="utf-8"> <title></title> </htad> <body> <script> fetch('http://localhost:3000/api/aaa') // 发送请求 .then(res=>res.json()) // 设置json解析 .then(res=>{ // 访问成功后将结果打印出来 console.log(res) fetch('http://localhost:3000/api/bbb') // 发送请求 .then(res=>res.json()) // 设置json解析 .then(res=>{ // 访问成功后将结果打印出来 console.log(res) }) </script> </body> </html> -
爬虫
// Command Window npm init // 创建package.json文件 npm i --save cheerio // 私有安装cheerio模块 // Server.js var http = require("http") var https = require("https") var cheerio = require("cheerio") // 导入cheerio模块,这个模块用于分析html代码 var url = require("url") http.createServer((req,res)=>{ res.writeHead(200,{ "Content-Type":"application/json;charset=utf-8", "access-control-allow-origin":"*" // 用于写入允许的网站访问,*代表全部。 }) var urlobj = url.parse(req.url,true) switch(urlobj.pathname){ case '/api/aaa': httpget((data)=>{ res.end(spider(data)) // 调用spider函数 }) break; default: res.end("404") } }).listen(3000,()=>{ console.log("Server Start") }) function httpget(cb){ var data = "" https.get('https://i.maoyan.com/',(res)=>{ // 发送请求获取到html代码 res.on("data",(chunk)=>{ data += chunk }) res.on("end",()=>{ cb(data) }) }) } function spider(data){ let $ = cheerio.load(data) // 将数据转换 let $moviewlist = $(".column.content") // 找出class="column content"的标签 let movies = [] $moviewlist.each((index,value)=>{ // 将数据传入并回调写到movies中 movies.push({ title:$(value).find(".title").text(), grade:$(value).find(".grade").text(), actor:$(value).find(".actor").text() }) }) return JSON.stringify(ovies) // 返回JSON的数据到前端即可。 } // index.html <!DOCTYPE html> <html lang='en'> <head> <meta charset="utf-8"> <title></title> </htad> <body> <script> fetch('http://localhost:3000/api/aaa') // 发送请求 .then(res=>res.json()) // 设置json解析 .then(res=>{ // 访问成功后将结果打印出来 console.log(res) }) </script> </body> </html>
url模块
-
node:url
模块提供用于网址处理和解析的实用工具。 可以使用以下方式访问它:const url = require('node:url');
,注意单个文件时需要写为cjs格式。 -
url模块用于将url对象转为字符串,也可以将字符串转为url对象。
-
但是我们之前用的是旧版的url,现在新版出来了肯定要学的对吧。
-
新版是以WHTWG API的并且url对象中还加入了“username”和“password”属性。
-
input
的主机名中出现的 Unicode 字符将使用 算法自动转换为 ASCII。 -
如果事先不知道
input
是否是绝对的网址并且提供了base
,则建议验证URL
对象的origin
是否符合预期。说白了就是判断url是否合规,不合规就使用base/input的方式并合规化。 -
旧版的使用
const url = require("url") // 导入url模块 const surl = "https://baidu.com/index.html?id=12" const parsedStr = url.parse(surl,True) // 解析url字符串,加true是将值按字典格式,不加是字符串 console.log(parsedStr) const url = require('url') const urlObject = { protocol:'https', slashes:true, auth:null, host:'www.baidu.com:443', port:'443', hostname:'www.baidu.com', hash:'#tag=110', search:'?id=8&name=mouse', query:{id:'8',name:'mouse'}, pathname:'/ad/index.html', path:'/ad/index.html?id=8&name=mouse' } const parsedObj = url.format(urlobject) // 组成完整的url console.log(parsedObj) const url = require('url') var a = url.resolve('/one/two/three','four') // url的拼接,不加/是替换最后一个单词,加了才是拼接 var b = url.resolve('http://example.com/','/one') var c = url.resolve('http://example.com/one','/two') // 替换域名后面的路径b和c结果一样 console.log(a+"."+b+"."+c) -
新版的使用
const myURL = new URL("http://www.baidu.com:8080/p/a/h?html=1&page=15","http://www.baidu.com:8080") // url需要两个参数,第一个是要分析的url,第二个是指定的域名(不包含路径) console.log(myURL.hash); // 获取网址的片段部分 myURL.hash = 'baz'; // 设置网址的片段部分 console.log(myURL.host); // 获取网址的主机部分 myURL.host = 'example.com:82'; // 设置网址的主机部分 console.log(myURL.hostname); // 获取网址的主机名,hostname和host区别在于,hostname不包含端口 myURL.hostname = 'www.baidu.com' // 设置网址的主机名 console.log(myURL.href); // 获取序列化网址 myURL.href = 'https://example.com/bar'; // 设置序列化网址 console.log(myURL.origin); // 获取网址的源的只读的序列化。 console.log(myURL.password); // 获取网址的密码部分。 myURL.password = '123'; // 设置网址的密码部分。 console.log(myURL.pathname); // 获取网址的路径部分。 myURL.pathname = '/abcdef'; // 设置网址的路径部分 // 端口值可以是数字,也可以是包含 `0` 到 `65535`(含)范围内的数字的字符串。 将值设置为给定 `protocol` 的 `URL` 对象的默认端口将导致 `port` 值成为空字符串 (`''`)。 console.log(myURL.port); // 获取网址的端口部分。 myURL.port = '443'; // 设置网址的端口部分。 console.log(myURL.protocol); // 获取网址的协议部分。 myURL.protocol = 'ftp'; // 设置网址的协议部分 // 特别计划 // WHATWG URL 标准认为少数 URL 协议方案在解析和序列化方面是特殊的。 当使用这些特殊协议之一解析网址时,`url.protocol` 属性可能会更改为另一种特殊协议,但不能更改为非特殊协议,反之亦然。 // 例如http协议会更改为https协议,但是,从 `http` 更改为假设的 `fish` 协议并不是因为新协议并不特殊。同样,也不允许从非特殊协议更改为特殊协议。 console.log(myURL.search); // 获取网址的序列化的查询部分。 myURL.search = 'abc=xyz'; // 设置网址的序列化的查询部分 // 当使用 `.searchParams` 修改 `URL` 时要小心,因为根据 WHATWG 规范,`URLSearchParams` 对象使用不同的规则来确定要对哪些字符进行百分比编码。 例如,`URL` 对象不会对 ASCII 波浪号 (`~`) 字符进行百分比编码,而 `URLSearchParams` 将始终对其进行编码 console.log(myURL.search); myURL.searchParams.sort(); console.log(myURL.username); // 获取网址的用户名部分。 myURL.username = '123'; // 设置网址的用户名部分 coonsole.log(url.format(myURL,{unicode:true})); // 格式化url,将其不规范字符按百分比编码。加上unicode就是按万国码方式编码。 auth:true // 序列化时包含username和password fragment:true // 序列化时包含片段 search // 序列化时包含搜索查询 unicode // 序列化时用unicode编码而不是Punycode编码。 console.log(url.domainToASCII('español.com')); // Punycode ASCII 序列化 console.log(url.domainToUnicode('xn--fiq228c.com')) // Unicode序列化 const { fileURLToPath } = require('node:url'); fileURLToPath('file:///你好.txt'); // 此函数可确保正确解码百分比编码字符,并确保跨平台有效的绝对路径字符串。 const { pathToFileURL } = require('node:url'); new URL('/foo#1', 'file:'); pathToFileURL('/foo#1'); // 该函数确保 path 被绝对解析,并且在转换为文件网址时正确编码网址控制字符。 console.log(urlToHttpOptions(myURL)); // 该实用函数按照 http.request()和 https.request() API 的预期将网址对象转换为普通选项对象。 protocol // 要使用的协议。 hostname // 要向其触发请求的服务器的域名或 IP 地址。 hash // 网址的片段部分。 search // 网址的序列化的查询部分。 pathname // 网址的路径部分。 path // 请求的路径。 href // 序列化的网址。 port // 远程服务器的端口。 auth // 基本身份验证
fs模块
-
fs模块在调用里面的方法时会发现,调用的方法都是回调函数的形式,但是回调函数是异步的,当一个没有完成任务后面的就会报错。所以我们要用到方法后面加上Sync再调用就是同步的了,当一条命令没有执行完成就不会执行下面的一条命令,但是他的错误是系统抛出的,我们需要使用异常处理捕获一下。
-
基本使用
const fs = require('fs'); // 同步,同步缺点在于你在使用同步时,其他用户就会停止响应。导致断开。 try{ fs.mkdirSync('a') }catch(err){ console.log(err) } // 所以我们需要使用异步实现等待效果,每个方法都有 const fs = require("fs").promises fs.readdir("./a").then(async (data)=>{ // 设定允许等待 let arr = [] // 创建数组 data.forEach(item=>{ // 调出所有的文件名 arr.push(fs.unlink('./a/${item}')) // 将掉出执行放入数组 }) await Promise.all(arr) // .all等待数组中任务完成,await等待数组完成 await fs.rmdir('./a') // 等待文件夹删除 // await Promise.all(data.map(item=>fs.unlink('./a/${item}'))) // 等同上面的这几行代码,.map是迭代,将item传入并执行删除文件的操作后返回,.all等待数组中任务完成 }) // await fs.rmdir('./a') // 异步 fs.mkdir("a",(err)=>{ // 创建文件夹 console.log(err); }) fs.rename("./a","./b",(err)=>{ // 文件夹重命名 console.log(err) }) fs.rmdir('b',(err)=>{ // 删除文件夹 console.log(err) }) fs.writeFile("./b/a.txt","wello world\n",(err)=>{ // 写入文件 console.log(err); }) fs.appendFile("./b/a.txt","wello world",(err)=>{ // 追加文件 console.log(err); }) fs.readFile('./b/a.txt','utf-8',(err,data)=>{ //查看文件并以utf-8编码,默认是Buffer console.log(err); console.log(data.toString('utf-8')); // Buffer对象转为utf-8编码 }) fs.unlink('./b/a.txt',(err)=>{ // 删除文件 console.log(err); }) fs.readdir('./a',(err,data)=>{ // 查看文件夹下的对象 data.foorEach(item=>{ fs.unlink('./a/${item}',(err)=>{}) }) }) fs.stat('./a',(err,data)=>{ // 查看文件夹下的文件以及文件的详细信息 console.log(data.isFile()); }) -
stream流模块,用于大文件的读写,文件过于大不可能一次读写完成,需要使用数据流的形式读写数据,分成小的包来接收。用时间换取性能的不足。
var fs = require("fs"); var rs = fs.createReadStream('sample.txt','utf-8'); // 创建一个读取流 rs.on('data',function (chunk){ // 读取数据传入函数 console.log(chunk); }); rs.on('end',function(){ // 读取结束 console.log('end'); }) rs.on('error',function (err){ // 读取出现错误 console.log(err); }) const ws = fs.createWriteStream("./a.txt",'utf-8') // 创建写入流 ws.write("1111") // 写入数据 ws.write("2222") ws.end() // 结束结束 const readStream = fs.createReadStream("./1.txt") // 创建读取流 const writeStream = fs.createWriteStream("./2.txt") // 创建写入流 readStream.pipe(writeStream) // 通过管道将一个文件写入另一个文件中 -
zlib,压缩文件和解压文件
const fs = require('fs') const zlib = require('zlib') const gzip = zlib.createGzip() const readstream = fs.createReadStream("./note.txt") const writestream = fs.createWriteStream("./note2.txt") readstream .pipe(gzip) .pipe(writestream) // 你在给前端发送gzip包时需要指定,不然发送到前端的就是乱码。在请求头中写入{"Content-Encoding":"gzip"}。 // 服务器发送一个文件时可以通过读取流并通过管道给res到前端。
crypto
-
crypto模块用于提供加密和哈希算法,通过c/c++实现这些算法后,通过cypto这个模块暴露为JavaScript接口。
-
md5时一种常见的哈希算法,用于给任意数据一个签名,这个签名通常用一个十六进制的字符串表示(不可逆)。
const crypto = require("crypto"); const hash = crypto.createHash("md5"); // 指定加密方式md5或sha1 hash.update("hello world") // 写入要生成哈希值的数据,默认时utf-8编码,也可以使用Buffer编码的字符。 console.log(hash.digest("hex")) // 十六进制显示哈希值 -
Hmac算法也是一种哈希算法,他可以利用md5或SHA1算法。Hmac还需要一个密钥,通过密钥来保证数据的安全。
const crypto = require("crypto") const hash = crypto.createHmac("sha256","alex") // 生成Hmac对象并指定加密方式和密钥,也可以时md5、sha1。 hash.update("12345") console.log(hash.digest("hex")) -
aes是一种常见的对称加密算法,加解密需要用到密钥才可以。
const crypto = require("crypto"); function encrypt(key,iv,data){ // 加密 // 使用aes加密算法,把key转为buffer编码,iv是向量值 let decipher = crypto.createCipheriv("aes-256-cbc",Buffer.from(key),iv); return decipher.update(data,'binary','hex')+decipher.final('hex'); // 将数据加入并按16进制返回 } function decrypt(key,iv,crypted){ // 解密 crypted = Buffer.from(crypted,"hex").toString("binary"); // 将16进制的密文转为binary let decipher = crypto.createDecipheriv('aes-256-cbc',key,iv); // 创建解密 // 将密文传入解密,并转为utf-8编码返回 return decipher.update(crypted,'binary','utf8')+decipher.final('utf8'); } let key = "1234567890abcdef1234567890abcdef"; // 256需要32位 let iv = "1234567890abcdef"; // 需要16位 let data = 'keddddd'; // 数据随便写 let cryted = encrypt(key,iv,data); console.log(cryted) console.log(decrypt(key,iv,cryted));
Small module
querystring
-
使用
const querystring = require('querystring') var parsed = querystring.parse('x=3&y=4') // 将from表单数据解析为字典对象 var parsed1 = querystring.stringify(parsed) // 将字典对象转为from表单数据 console.log(parsed1) var escaped = querystring.escape("https://www.baidu.com") // 将unicode按百分比编码转换 var unescaped = querystring.unescape("https%3A%2F%2Fwww.baidu.com") // 将百分比编码转为为unicode console.log(ecaped,unescaped)
events
-
use
const EventEmitter = require("events") // 导入events模块 const event = vew EventEmitter() // 创建一个event对象 event.on("play",(data)=>{ // 编写一个监听事件 console.log("aaa",data) }) setTimeout(()=>{ // 设置等待两秒 event.emit("play","bbb") // 出发指定的事件 },2000) // 注意event对象一定要创建好,不要为了节约代码导致出现,一个事件被多次创建,导致出发的时候触发了多个。
路由
-
基础
// manage.js const server = require("./main.js") // 导入main.js中的暴露方法 const api = require("./api") // 导入api.js中的暴露元素 const route = require("./route") // 导入route.js中的暴露元素 server.run(api); // 调用server.run方法将数组传入 server.run(route); server.start(); // 调用server.start()的开始方法 // main.js const http = require("http") // 调用http模块 const Router = {} // 写一个空字典 function run(url){ // 将传入进来的数组元素放入Router字典中。 Object.assign(Router,url); } function start(){ // 开启服务器方法 http.createServer((req,res)=>{ const myURL = new URL(req.url,"http://127.0.0.1") // 服务 try{ // 异常处理 Router[myURL.pathname](req,res); // 字典中寻找匹配的元素 } catch (err){ Router["/404"](req,res); } }).listen(3000,()=>{ console.log("server start"); }) } module.exports = { // 暴露方法 start, run } // api.js const fs = require("fs") function render (req,res,data,code=200){ // 编写读取 res.writeHead(code,{"Content-Type":"application/json;charset=utf8"}) res.write(data); res.end() } api = {"/api/login":(req,res)=>{ // 编写get请求并获取数据 const myURL = new URL(req.url,"http://127.0.0.1") if(myURL.searchParams.get("username") === "alex" && myURL.searchParams.get("password")=== "123"){ render(req,res,'{"error":001,"data":"ok"}'); }else{ render(req,res,'{"error":002}'); } },"/api/loginpost":(req,res)=>{ // 编写post请求并获取数据 var post = ""; req.on("data",chunk=>{ post+=chunk; }) req.on("end",()=>{ console.log(post) post = JSON.parse(post) if(post.username === "alex" && post.password === "123"){ render(req,res,'{"error":001,"data":"ok"}'); }else{ render(req,res,'{"error":002}'); } }) } } module.exports = api // route const fs = require("fs") const path = require("path") const mime = require("mime") // mime模块中的getType方法用来将后缀转为指定的请求文件类型。 function render (res,path,type="text/html",code=200){ res.writeHead(code,{"Content-Type":`${type};charset=utf8`}) res.write(fs.readFileSync(path),"utf-8"); res.end() } route = {"/login":(req,res)=>{render(res,"./static/login.html")}, // 静态过去文件 "/home":(req,res)=>{render(res,"./static/home.html")}, "/404":(req,res)=>{ if(readStaticFile(req,res)){ return } render(res,"./static/404.html",code=404) } } function readStaticFile(req,res){ // 动态过去文件,如css、js、asp const myURL = new URL(req.url,"http://127.0.0.1:3000") const pathname = path.join(__dirname,"/static",myURL.pathname) if(myURL.pathname==="/")return false if(fs.existsSync(pathname)){ render(res,pathname,mime.getType(myURL.pathname.split(".")[1])) return true; }else{ return false; } } module.exports = route // ./static/login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> <link rel="stylesheet" href="/css/login.css"> </head> <body> <div> <div>username:<input id="username" type="text"/></div> <div>password:<input id="password" type="password"/></div> <div>button:<input id="button" type="button" value="button"/></div> <div>buttonpost:<input id="buttonpost" type="button" value="buttonpost"/></div> </div> <script> var button = document.querySelector("#button"); var buttonpost = document.querySelector("#buttonpost"); var username = document.querySelector("#username"); var password = document.querySelector("#password"); button.onclick = ()=>{ fetch(`/api/login?username=${username.value}&password=${password.value}`).then(res=>res.text()).then(res=>{ console.log(res) }) } buttonpost.onclick = ()=>{ fetch(`/api/loginpost`,{ method:"POST", body:JSON.stringify({ username:username.value, password:password.value }), headers:{ "Content-Type":"application/json" } }).then(res=>res.text()).then(res=>{ console.log(res) }) } </script> </body> </html> // ./static/css/login.css #username{ background-color:red; }
Express
-
基于Nodejs平台的快速、开放、简洁的web开发框架。
-
express是一个基于Nodejs平台的极简、灵活的web应用开发框架,它提供一系列强大的特性,帮招我们创造各种web和移动设备的应用。
-
丰富的HTTP快捷方法和任意排列组合的Connect中间件,让我创建强壮、友好的api变得既快速又简介。
-
安装
npm install express --save -
简单搭建server端
const express = require("express") const app = express() app.get("/",(req,res)=>{ res.write("hello world"); res.end(); }) app.get("/1",(req,res)=>{ res.send("hello world"); }) app.get("/2",(req,res)=>{ res.send({"name":"alex","age":15}); }) app.get("/3",(req,res)=>{ res.send(`<h1>hello world!</h1>`); }) app.listen(3000,()=>{ console.log("Server Start"); }) -
字符串模式
"/ab?cd" // abcd,acd:代表可选 "/ab/:id" // 匹配ab/后面的字符,再有/的话需要再加“/:id/:id2” "/ab+cd" // abcd,abbcd,abbbcd,中间可以加入左右边的多个相同字符。 "/ab*cd" // ab和cd之间加任意多个不同的字符 "/ab(cd)?e" // abe,abcde:代表可选的字符串
中间件
-
认识中间件
const express = require("express") const app = express() var cb1 = function (req,res,next){ console.log("1") res.dea = "baba" // 在res中加一个数据 next(); } var cb2 = function (req,res,next){ console.log(res.kea) // 调用res中自己添加的数据 next(); } app.get("/",[cb1,cb2]) // 这里的回调函数,在node中叫做中间件,中间件可以执行多个,如写成数组在外面调用。但是需要注意的是你要使用下一个中间件需要在上一个中间件中写入next形参并调用才可以。 app.get("/3",(req,res,next)=>{ // 也可以把中间件写成这样,这样不过不美观 res.send(`<h1>hello world!</h1>`); next(); },(req,res)=>{ res.send(`<h1>hello world!</h1>`); }) app.listen(3000,()=>{ console.log("Server Start"); }) -
Express是一个自身功能极简,完全是路由和中间件组成的一个web开发框架。
-
中间件(Middleware)是一个函数,它可以访问请求对象(request Object),响应对象(response Object),和web应用中处于请求-响应循环流程中的中间件,一般被命名为Next的变量。
-
中间件的功能包括:执行任何代码、修改对象和响应对象、终结请求-响应循环和调用堆栈中的下一个中间件。
-
如果当前中间件没有终极请求-响应循环,则必须调用next方法将控制全交给下一个中间件,否则请求就会挂起。
-
Express应用可以如下几种中间件:应用及中间件、路由级中间件、错误处理中间件、内置中间件和第三方中间件。
const express = require("express") const IndexRouter = require("./a") const app = express() var cb1 = function (req,res,next){ console.log("1") next(); } // 1.应用及中间件绑定到app对象,使用app.use()和app.METHOD(),其中,METHOD是需要处理的HTTP请求的方法。他下面的只要访问就会执行给定的函数,也可以指定路径执行给定的函数。 app.use(cb1) app.use("/",cb1) app.get("/6",[cb1]) // 2.路由级别的中间件,就是路由分发到多个文件中。访问指定的路径下的路径就会被转到指定的文件中。 app.use("/api",IndexRouter); // a.js const express = require("express"); const router = express.Router(); router.get("/home",(req,res)=>{ res.send("api/home") }) module.exports = router; // 3.错误处理中间件,和其他中间件定义类似,只是要使用4个参数。 app.use(function(err,req,res,next){ res.status(404).send("Something broke!") }) // 4.静态中间件,是用于托管静态资源来用的,写文件夹名即可。 app.use(express.static("files")) app.use(express.static("/static","files")) // 5.get、post、put、delete请求既数据。需要设置解析才可以获得到post请求的数据。express.urlencodedfrom用于表单格式的数据,express.json用于json格式的数据 app.use(express.urlencoded({extended:false})) app.use(express.json()) app.get("/aaa",(req,res)=>{ console.log(req.query) // 获取get方式发送到后端的数据 res.send("login-success") }) app.post("/aaa",(req,res)=>{ console.log(req.body) // 用于获取post方式发送到后端的数据 res.send({ok:1}) }) app.listen(3000,()=>{ console.log("Server Start"); })
摸板渲染
-
服务器渲染,后台嵌套摸板,渲染摸板,将渲染好的摸板返回到前端,不需要前端做太多的操作。
-
前后端分离是后端提供页面的返回和数据的筛选过滤,前端通过ajax发送请求到后端拿json数据并渲染摸板,达到效果。
-
安装渲染模块:
npm install ejs
。// 配置摸板引擎指定的文件类型和路径 app.set("views","./views"); app.set("view engine","ejs"); // 渲染返回,访问时不需要加后缀 app.get("/",(req,res)=>{ // 渲染摸板需要使用render方法才可以,还可以传输数据 res.render("login",{"title":"11111"}); }) app.get("/home",(req,res)=>{ // 用于跳转页面 res.redirect("/login") // views/login.ejs <body> // 拿到数据并通过这种方式渲染 <h1>推荐-<%=title%></h1> // <% %> 用于流程控制语句 // <%= %> 用于原文输出 // <%- %> 用于html会被浏览器解析的 // <%# %> 注释标签 // <% include("user/show.ejs",{"user":true}) %> 导入公共的摸板内容,第二个参数是将数据导入公共摸板,用于判断摸板中的数据需不需要显示,等操作的。 </body> // 支持直接渲染html文件 app.set("views","./views"); app.set("view engine","html") app.set('html',require("ejs").renderFile) // 读取和设置cookie,需要在生成器生成的骨架下才可以,应为里面已经处理过了。 app.get("/",function(req,res,next){ res.cookie("gender","male") console.log(req.cookies); })
生成器
-
通过应用生成器工具
express-generator
可以快速创建一个应用的骨架。$ npx express-generator -e // 8.2.0 及更高版本使用 $ npm install -g express-generator // 较老的 Node 版本,请通过 npm 将 Express 应用程序生成器安装到全局环境中并使用。 $ express -
-h
参数可以列出所有可用的命令行参数$ express -h Usage: express [options] [dir] Options: -h, --help 输出使用方法 --version 输出版本号 -e, --ejs 添加对 ejs 模板引擎的支持 --hbs 添加对 handlebars 模板引擎的支持 --pug 添加对 pug 模板引擎的支持 -H, --hogan 添加对 hogan.js 模板引擎的支持 --no-view 创建不带视图引擎的项目 -v, --view <engine> 添加对视图引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默认是 jade 模板引擎) -c, --css <engine> 添加样式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默认是普通的 css 文件) --git 添加 .gitignore -f, --force 强制在非空目录下创建 -
如下命令创建了一个名称为 myapp 的 Express 应用。此应用将在当前目录下的 myapp 目录中创建,并且设置为使用 模板引擎(view engine):
$ express --view=ejs myapp create : myapp create : myapp/package.json create : myapp/app.js create : myapp/public create : myapp/public/javascripts create : myapp/public/images create : myapp/routes create : myapp/routes/index.js create : myapp/routes/users.js create : myapp/public/stylesheets create : myapp/public/stylesheets/style.css create : myapp/views create : myapp/views/index.pug create : myapp/views/layout.pug create : myapp/views/error.pug create : myapp/bin create : myapp/bin/www -
然后安装所有依赖包
$ cd myapp $ npm install -
在 Windows 命令行中,使用如下命令:
set DEBUG=myapp:* & npm start
。 -
在 Windows 的 PowerShell 中,使用如下命令:
$env:DEBUG='myapp:*'; npm start
。 -
然后在浏览器中打开
http://localhost:3000/
网址就可以看到这个应用了。 -
通过生成器创建的应用一般都有如下目录结构:
. ├── app.js ├── bin │ └── www ├── package.json ├── public │ ├── images │ ├── javascripts │ └── stylesheets │ └── style.css ├── routes │ ├── index.js │ └── users.js └── views ├── error.pug ├── index.pug └── layout.pug 7 directories, 9 files
MongoDB
-
关系型数据库:通过sql语句增删改查操作,保持事务的一致性,事务机制
-
非关系型数据库:轻量、高效、自由。
-
由于MongoDB独特的数据处理方式,可以将热点数据加载到内存。故而对查询来讲,会非常快。
-
同时由于采用BSON的方式存储数据,故而对JSON格式数据具有非常好的支持性以及友好的表结构修改性,文档式的存储方式,数据友好可见;
-
数据库的分片集群负载具有非常好的扩展性以及非常不错的自动故障转移。
-
安装数据库
// 去连接下载软件 https://docs.mongodb.coom/manual/administration/install-community/ // 启动数据库 mongod --dbpath d:/data/db mongo -
操作数据库
// 显示命令提示 help db.help() db.test.help() db.test.find().help() // 创建/切换数据库 use music // 查询数据库 show dbs // 查看当前使用的数据库 db.getName() // 显示当前db状态 db.stats() // 查看当前db版本 db.version() // 查看当前db的连接机器地址 db.getMongo() // 删除数据库 db.dropDatabase() // 数据库中插入一个聚集集合,并设置最大 空间为5m,最多5000个文档。 db.createCollection("users",{size:5242880,cappde:true,max:5000}); // 得到指定名称的聚集集合 db.getCollection("account"); // 得到当前db的所有聚集集合 db.getCollectionNames(); // 显示当前db所有聚集的状态 db.printCollectionStats(); // 删除 db.users.drop(); // 添加数据 db.users.save({name:"abc",age:25,sex:true}); db.users.save({name:"bcd",age:24,sex:true},{name:"cde",age:23,sex:true}); // 修改数据,set修改,inc是自加修改 db.users.update({age:25},{$set:{name:"aaa"}},false,true); db.users.update({name:"bcd"},{$inc:{age:50}},false,true); // 删除数据,括号中不加代表删除所有 db.users.remove({age:23}); // 查询所以记录 db.userinfo.find(); // 查询某字段去重后数据 db.userinfo.disfind("name"); // 查询age=22的记录 db.userinfo.find({"age":22}); // 查询age>22并且age<49的记录 db.userinfo.find({age:{$gt:22,$lt:49}}); // 查询age>=22并且age<=49的记录 db.userinfo.find({age:{$gte:22,$lte:49}}); // 查询那么中包含mongo的数据 db.userinfo.find({name:/mongo/}); // 查询name中以mongo开头的 db.userinfo.find({name:/^mongo/}); // 查询指定的列,1代表显示,0代表不显示。 db.userinfo.find({},{name:1,age:0}) // 使用升序查询姓名,如果重复使用降序查询age db.userinfo.find().sort({name:1,age:-1}); // 查询10条到50条的数据 db.userinfo.find().skip(10).imit(50); // or的查询 db.userinfo.find($or:{{age:22},{age:25}}); // 查询第一条数据 db.userinfo.findOne(); // 查询某个结果集的记录条件 db.userinfo.find({age:{$gle:14}}).count();
Use nodejs Manage mongodb
-
使用nodejs操作mongodb需要安装一个模块才可以
npm install mongoose
。生成器生成的模型中使用。// ./app.js var loginRouter = require('./routes/login'); app.use("/login",loginRouter); // ./bin/www require("../config/db.config"); // ./config/db.config.js const mongoose = require("mongoose"); // 连接名为kerwin_project的数据库,如果没有会自动创建。 mongoose.connect("mongodb://127.0.0.1:27017/userinfo") // ./model/loginmodel.js const mongoose = require("mongoose"); const UserType = { username:String, password:String, age:Number } // 记住user是在数据库中加s的。 const UserModel = mongoose.model("user",new mongoose.Schema(UserType)) module.exports = UserModel // ./controllers/LoginController.js var LoginService = require('../services/LoginService'); const LoginController = { login:async (req, res, next)=>{ const {username,password} = req.body; var data = await LoginService.login(username,password); if(data.length === 0){ res.redirect("/login"); }else{ res.redirect("/home"); } } } module.exports = LoginController; // ./services/LloginServices.js var UserModel = require('../model/loginModel') const LoginService = { loginadd:(username,password)=>{ // 增加数据 return UserModel.create({username:"alex",password:"1234",age:"19"}) .then(data=>{console.log(data);}); }, logindel:(username,password)=>{ // 删除数据 return UserModel.deleteOne({username:"alex"}); }, loginput:(username,password)=>{ // 更新数据 return UserModel.updateOne({username:"alex"},{username:"pq"}); }, login:(username,password)=>{ // 查询数据 return UserModel.find({username,password},["username"]).sort({createTime:-1}) }, }; module.exports = LoginService; // ./routes/login.js var express = require('express'); var router = express.Router(); var LoginController = require('../controllers/LoginController'); /* GET home page. */ router.get('/', function(req, res, next) { res.render('login', { title: 'Express' }); }); router.post('/',LoginController.login); module.exports = router; -
接口规范,简单的来说就是url地址中只含名词表示资源,使用http动词表示动作进行操作资源。服务器上每一种资源,比如一个文件,一张图片,都有对应的url地址,如果我们的客户端需要对服务器上的这个资源进行操作,就需要通过http协议执行相应的动作来操作它。
-
业务关系,router.js负责将请求分发给C层、controller.jsC层负责处理业务逻辑、views负责展示页面、model负责处理数据。
登录鉴权
Cookie&Session
-
我们知道,HTTP是无状态的。也就是说,HTTP请求和响应间无法维持状态,都是一次性的,它不知道前后的请求发生了什么。但有的场景下需要我们维护状态。就有了Cookie和Session了。
-
Cookie用户端存储的凭证,用于和请求一起发送到服务器来判断你的身份。
-
Session是存储在服务器的凭证,应为Cookie到来后如果不是用验证算法是无法知道Cookie是合法的。所以需要在服务器的Session中也存储一份用来判断用户的合法性和是否过期性。
-
nodejs操作Session比较麻烦,我们使用一个模块来实现其操作
npm install express-session
andnpm install connect-mongo
。// app.js var session = require("express-session"); var MongoStore = require("connect-mongo"); app.use(session({ name:"token", secret:"ertergergergdsfsg", resave:true, // true每次访问之后重新计算时间 saveUninitialized:true, // 强制将未初始化的session存储 cookie:{ maxAge:1000 * 60 * 10, // 过期时间 secure:false, // 为true时候表示只有https协议才可以访问cookie }, rolling:true, // 为true表示超时前刷新,cookie会重新机时:为false表示在超时前刷新多少次,都是按照第一次刷新开始计时。 store:MongoStore.create({ mongoUrl:"mongodb://127.0.0.1:27017/usersession", ttl:1000 * 60 * 10 // 过期时间 }) })); app.use((req,res,next)=>{ if(req.url.includes("login")){ next(); return } if(req.session.user){ req.session.date = Date.now(); next(); }else{ res.redirect("/login"); } }) // ./routes/login.js var express = require('express'); var router = express.Router(); var LoginController = require('../controllers/LoginController'); /* GET home page. */ router.get('/', function(req, res, next) { res.render('login', { title: 'Express' }); }); router.post('/',LoginController.login); router.delete('/',LoginController.logindel); module.exports = router; // ./controllers/LoginController.js var LoginService = require('../services/LoginService'); const LoginController = { login:async (req, res, next)=>{ const {username,password} = req.body; var data = await LoginService.login(username,password); if(data.length === 0){ res.redirect("/login"); }else{ req.session.user = data[0]; res.redirect("/home"); } }, logindel:async(req, res, next)=>{ console.log("aaaaa") req.session.destroy(()=>{ res.send({ok:0}); }) }, } module.exports = LoginController; // ./views/login.ejs <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <form action="/login" method="post"> <div>用户名:<input name="username" type="text" ></div> <div>密 码:<input name="password" type="password" ></div> <input type="submit" value="Submit"> </form> <div id="loguot">退出登录</div> <script> var loguot = document.querySelector("#loguot"); loguot.onclick = ()=>{ fetch(`/login`,{ method:"DELETE", }) } </script> </body> </html>
Json Web Token
-
token解决了跨站请求伪造的问题和session的问题,通过用户携带一个可以被验证算法验证身份的方式来携带,解决了session的存储和跨站访问的问题。安装
npm install jsonwebtoken
。// 使用JWT来实现的维持用户状态,失去了后台的主动权,只等等待前端的过期时间结束才可以取消登录。前后端必须都需要写拦截器,这样才可以实现拦截。 // ./config/JWT.js const jsonwebtoken = require("jsonwebtoken"); const secret = "abc" // 密钥 const JWT = { generate(value,exprires){ // 编写加密算法设置内容和过期时间(expiresIn) return jsonwebtoken.sign(value,secret,{expiresIn:exprires}) }, verify(token){ // 解密token并异常捕获 try{ return jsonwebtoken.verify(token,secret); }catch(e){ return false; } } } module.exports = JWT // ./app.js var JWT = require("./config/JWT"); app.use((req,res,next)=>{ if(req.url.includes("login")){ next(); return } const token = req.headers['authorization']?.split(' ')[1]; if (token){ console.log(token); const payload = JWT.verify(token) if(payload){ const newToken = JWT.generate({_id:payload._id,username:payload.username},'1h'); res.header('Authorization',newToken); next(); }else{ res.status(401).send({errCode:-1,errInfo:"tokenNot"}) } }else{ next(); } }) // ./controllers/LoginController.js var LoginService = require('../services/LoginService'); var JWT = require("../config/JWT"); const LoginController = { login:async (req, res, next)=>{ const {username,password} = req.body; var data = await LoginService.login(username,password); if(data.length === 0){ res.redirect("/login"); }else{ console.log("aaaaa") const token = JWT.generate({ _id:data[0]._id,username:data[0].username },'1h') res.header("Authorization",token); // 设置token res.send({ok:1}); } }, logindel:async(req, res, next)=>{ console.log("aaaaa") res.send({ok:0}); }, } module.exports = LoginController; // ./routes/login.js var express = require('express'); var router = express.Router(); var LoginController = require('../controllers/LoginController'); /* GET home page. */ router.get('/', function(req, res, next) { res.render('login', { title: 'Express' }); }); router.post('/',LoginController.login); router.delete('/',LoginController.logindel); module.exports = router; // ./routes/index.js var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/data', function(req, res, next) { res.send({ data: 'asdf' }); }); router.get('/home', function(req, res, next) { res.render('home', { title: 'Express' }); }); module.exports = router; // ./views/home.ejs <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <div id='text' ></div> <!--调用axios.js--> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> <!--编写一个拦截器拦截出去和进来的请求--> axios.interceptors.request.use(function(config){ <!--发送请求时触发--> const token = localStorage.getItem('token'); config.headers.Authorization = `Bearer ${token}`; return config; },function (error){ return Promise.reject(error); }) axios.interceptors.response.use(function (response){ <!--请求来到后执行一次--> const {authorization} = response.headers authorization && localStorage.setItem("token",authorization) console.log(authorization) return response; },function (error){ <!--来到的请求异常后触发--> if(error.response.status === 401){ localStorage.removeItem("token"); location.href = '/login'; } return Promise.reject(error); }) </script> <script> var text = document.querySelector("#text"); <!--使用axios的请求类型来触发拦截器--> axios.get("/data").then(res =>{ text.value = res.data.data; }) </script> </body> </html> // ./views/login.ejs <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <div>用户名:<input id="username" type="text" ></div> <div>密 码:<input id="password" type="password" ></div> <input type="submit" id='login' value="Submit"> <input type="submit" id='logut' value="退出登录"> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> axios.interceptors.request.use(function(config){ const token = localStorage.getItem('token'); config.headers.Authorization = `Bearer ${token}`; return config; },function (error){ return Promise.reject(error); }) axios.interceptors.response.use(function (response){ const {authorization} = response.headers authorization && localStorage.setItem("token",authorization) console.log(authorization) return response; },function (error){ if(error.response.status === 401){ localStorage.removeItem("token"); location.href = '/login'; } return Promise.reject(error); }) </script> <script> var login = document.querySelector("#login"); var username = document.querySelector("#username"); var password = document.querySelector("#password"); login.onclick = ()=>{ axios.post("/login",{ username:username.value, password:password.value, }).then(res =>{ if(res.data.ok === 1){ location.href = '/home'; }else{ alert("用户名或秘密错误!"); } }) } logut.onclick = ()=>{ localStorage.removeItem("token"); location.href = '/login' } </script> </body> </html>
文件上传
-
Multer是一个nodejs中间件,用于处理multipart/form-data类型的表单数据,它主要用于上传文件。它是写在busboy之上非常高效
npm install multer
。// ./routes/index.js var express = require('express'); var router = express.Router(); var LoginController = require('../controllers/LoginController'); const multer = require("multer"); const upload = multer({dest:'public/uploads/'}) /* GET home page. */ router.get('/data', function(req, res, next) { res.send({ data: 'asdf' }); }); router.get('/home', function(req, res, next) { res.render('home', { title: 'Express' }); }); router.post('/home',upload.single('avatar'),LoginController.home); module.exports = router; // ./controllers/LoginController.js var LoginService = require('../services/LoginService'); var JWT = require("../config/JWT"); const LoginController = { home:async (req, res, next)=>{ if(req.file){ console.log(req.body,`/uploads/${req.file.filename}`); }else{ console.log(req.body,`/images/default.png`); } res.send({ok:1}); } } module.exports = LoginController; // ./views/home.ejs <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <form action='/home' method='POST' enctype="multipart/form-data"> <div>username<input type="text" name='username'></div> <div>password<input type="password" name='password'></div> <div>age<input type="number" name='age'></div> <div>avatar<input type="file" name='avatar'></div> <input type="submit" value='submit'> </form> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> axios.interceptors.request.use(function(config){ const token = localStorage.getItem('token'); config.headers.Authorization = `Bearer ${token}`; return config; },function (error){ return Promise.reject(error); }) axios.interceptors.response.use(function (response){ const {authorization} = response.headers authorization && localStorage.setItem("token",authorization) console.log(authorization) return response; },function (error){ if(error.response.status === 401){ localStorage.removeItem("token"); location.href = '/login'; } return Promise.reject(error); }) </script> <script> var text = document.querySelector("#text"); axios.get("/data").then(res =>{ text.value = res.data; }) </script> </body> </html> -
前后端分离上传文件
// ./routes/index.js var express = require('express'); var router = express.Router(); var LoginController = require('../controllers/LoginController'); const multer = require("multer"); const upload = multer({dest:'public/uploads/'}) /* GET home page. */ router.get('/data', function(req, res, next) { res.send({ data: 'asdf' }); }); router.get('/home', function(req, res, next) { res.render('home', { title: 'Express' }); }); // single是获取1个文件,array('file',12)是获取多个文件并最多获取12个文件。 router.post('/home',upload.single('avatar'),LoginController.homeput); module.exports = router; // ./views/home.js // 获取文件对象时,找到指定的文件对象后直接点files[0]发送到后端就可以了。 ... const params = new FormData(); params.append("kerwinfile",file.files[0]); params.append("username",this.username); const config = { headers:{ "Content-Type":"multipart/form-data" } } axios.post('/home',params,config).then(res => { this.imgpath = 'http://localhost:3000'+res.data; })
APIDOC
-
aipdoc是一个简单的RESTful API 生成工具,它从开骂注释中提取特定格式的内容生成文档。支持大多数语言,具体可使用apidoc lang命令行查看你所有的支持列表
npm install -g apidoc
。/** * @api {post} /login * @apiName login * @apiGroup group * @apiVersion 1.1.1 * * @apiParam {String} username 用户名 * @apiParam {String} password 密码 * * @apiSuccess (200) {number} ok 标识成功字段 * * @apiParamExample {multipart/form-data} *{ * username:'alex', * password:'1234' *} * * @apiSuccessExample {type} Success-Response: *{ * ok:1 *} * **/ -
生成使用命令
sqidoc -i src/ -o doc/
。可以在需要生成的目录下创建一个apidoc.json来配置其信息。{ "name":"name", "version":"1.2.2", "description:"描述", "title":"标题"。 }
Koa
-
koa是由Express原班人马打造的,致力于称为一个更小、更富有表达力、更健壮的web框架。使用koa编写web应用,通过组合不同的generator,可以免除功夫繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa不再内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写web应用变得的心应手。
-
install koa
npm install koa
。const Koa = require("koa"); const app = new Koa(); app.use( async(ctx) =>{ console.log(ctx.request.path); console.log(ctx.path); ctx.body = "hello koa2" }) app.listen(3000);
koa vs express
-
通常都会说koa是洋葱模型,这重点在于中间件的设计。但是按照上面的分析,会发现Express也是类似的,不同的是Express中间件的机制使用了Callback实现,这样如果出现异步则可能会使你再执行顺序上感到困惑,因此如果我们想做接口耗时统计、错误处理koa的这种中间件模式处理起来更方便些。最后一点响应机制很重要koa不是立即响应,是整个中间件处理成功再最外层进行了响应,而Expreess则是立即响应。
-
koa增加了一个Context的对象,作为这次请求的上下文对象。同时Context上也挂载了Request和Response两个对象。和Express类似,这两个对象都提供了大量的便捷方法辅助开发,这样的话对于在保存一些公有的参数变得更加合理。
-
express采用callback来处理异步,koa v1采用generator,koa v2采用async/await。generator和async/await使用同步的写法来处理异步,明显好于callback和promise。
-
Express基于connect中间件,线性模型;koa中间件采用洋葱模型(对于每个中间件,在成功一些事情后,可以非常优雅的将控制权传递给下一个中间件,并能够等待它成功,当后续的中中间件完成处理后,控制权又回到了自己)。
// express const express = require("express"); const app = express(); app.use((req,res,next)=>{ console.log("11111"); next(); console.log("333333"); res.send("hello world"); }) app.use((req,res,next)=>{ console.log("222222") }) app.listen(3000); // koa const koa = require("koa"); const app = new koa(); app.use( async(ctx,next) =>{ console.log("11111"); next(); console.log("333333"); res.send("hello world"); }) app.use(async(ctx,next)=>{ console.log("222222") }) app.listen(3000); -
koa需要的第三方模块
// koa是携带路由的需要单独下载路由模块 npm install koa-router // koa没有静态资源获取的方式,我们需要下载模块才可以。 npm install koa-static // 我们可以从上下文中直接获取参数ctx.query,字符串类型ctx.querystring。post请求处理需要使用中间件来解析数据到ctx.request.body中。 npm install koa-bodyparser // 在koa中实现摸板渲染还是需要下载第三方模块 npm install koa-views npm install ejs -
app注册于配置
// ./server.js const koa = require("koa"); const app = new koa(); const static = require("koa-static"); const path = require("path"); const bodyParser = require("koa-bodyparser"); const views = require("koa-views"); const router = require("./routes/index"); app.use(static( // 注册app使用静态资源 path.join(__dirname,"public") )) app.use(views(path.join(__dirname,'./view'),{ // 加载模板引擎 extension:'ejs' })) router.get("/",async (ctx,next)=>{ async ctx.render('home') // 自动在views/下寻找home文件,它是异步的必须加async }) app.use(bodyParser()); // 注册post数据解析app。 app.use(router.routes()).use(router.allowedMethods()); // 访问类型不对时抛出405并提示。 app.listen(3000); // ./router/home.js const Router = require("koa-router") const router = new Router(); router.get("/",async(ctx,next) =>{ console.log("11111"); next(); console.log("333333"); ctx.body = "hello world"; }) module.exports = router; // ./router/index.js const Router = require("koa-router") const router = new Router(); const home = require("./home"); // router.prefix("/api"); // 统一加前缀 router.use("/home",home.routes(),home.allowedMethods()); router.redirect("/","/home"); // 重定向 module.exports = router;
Cookie&Session
-
koa提供了上下文直接读取、写入cookie的方法。
ctx.cookies.get(name,[options]) // 读取上下文请求中的cookie ctx.cookies.set(name,value,[options]) // 在上下文中写入cookie -
koa-session-minmal适用于koa2的session中间件,提供存储介质的读写接口。
// npm install koa-session-minimal const session = require('koa-session-minimal'); app.use(session({ // 配置session并注册 key:"SESSION_ID", cookie:{ maxAge:1000*60 } })) app.use((ctx,next) =>{ // 配置未登录无法访问 if(ctx.url.includes("login")){ // 排除login接口 next() return } if(ctx.session.user){ ctx.session.mydate = Date.now(); // 重新设置一下session next(); }else{ ctx.redirect("/login"); } })
FileUploads
-
在koa中使用文件上传需要使用这个模块
npm install --save @koa/multer
和npm install --save multer
。const multer = require('@koa/multer'); const upload = multer({dest:'public/uploads/'}); // 上传单张照片 router.post("/",upload.single('avatar'), (ctx,next)=>{ console.log(ctx.request.body,ctx.file) ctx.body={ ok:1, info:"add user success." } }) // 上传多张照片 router.post("/",upload.fields([ { name:"avatar", maxCount:1 },{ name:"boop", maxCount:2 }, ]), (ctx,next)=>{ console.log(ctx.request.body,ctx.file) ctx.body={ ok:1, info:"add user success." } })
MongoDB
-
使用koa连接mongodb其实和express没有区别,但是我们还是写一遍吧。
// config/mongodb.js const mongoose = require("mongoose"); mongoose.connect("mongodb://127.0.0.1:27017/alex"); // models/model.js const mongoose = require("mongoose"); const Schema = mongoose.Schema const UserType ={ username:String, password:String, age:Number, avatar:String } const UserModel = mongoose.model("user",new Schema(UserType)); module.exports = UserModel;
MySQL
-
使用nodejs连接mysql需要安装mysql2这个模块
npm install mysql2
。const express = require("express") const app = express() const mysql2 = require("mysql2") const port = 9000 app.get("/", async (req,res)=>{ const config = getDBConfig() const promisePool = mysql2.createPool(config).promise(); let user = await promisePool.query("select * from students where name = ?",["李永强"]); console.log(user){ if (user[0].length){ res.send(user[0]) }else{ res.send({ code:-2, msg:"user not exsit" }) } } }) app.listen(post,()=>{ console.log(`Example app listening at http://localhost:${port}`) }) function getDBConfig(){ netrun{ host:"127.0.0.1", user:"root", port:3306, password:"", database:"alex", connectionLimit:1 // create one join } }
Socket
-
WebSocket并不是全新的协议,而是利用了HTTP协议来创建的连接。我们来看看WebSocket连接时如何创建的。首先,WebSocket连接必须由浏览器发起,因为请求协议是一个标准的HTTP请求。
GET ws://localhost:3000/ws/chat HTTP/1.1 Host:localhost Upgrade:websocket Connection:Upgrade Origin:http://localhost:3000 Sec-WebSocket-Key:client-random-string // 标识这个连接,并非加密数据。 Sec-WebSocket-Version:13 -
随后,服务器如果接受该请求,就会返回如下响应 :
HTTP/1.1 101 Switching Protocols Upgrade:websocket Connectioon:Upgrade Sec-WebSocket-Accept:server-random-string -
该响应代码101代表本次连接的HTTP协议既将被更改,更改的协议为Upgrade:websocket协议。
-
实现websocket的后端由两个模块
npm install ws
和npm install socket.io
。
ws
-
实现websocket的后端模块
npm install ws
。 -
服务端
const WebSocket = require("ws"); WebSocketServer = WebSocket.web.SocketServer; const wss = new WebSocketServer({port:8080}); // 创建所有人的对象 wss.on("connection",function connection(ws,req){ ws.on("message",function message(data,isBinary){ // 自己 wss.clients.forEach(function each(client){ // 其他人 if(client !== ws && client.readyState === WebSocket.OPEN){ // 判断不是自己的时候 client.send(data,{binary:isBinary}); // 给其他人发消息 } }); }); ws.send("Welcome to the chat room") }); -
客户端
var ws = new WebSocket("ws://localhost:8080"); ws.onopen = ()=>{ console.log("连接成功"); } ws.onmessage = (msgObj)=>{ console.log(msgObj); } ws.onerror = ()=>{ console.log("error"); } ws.send('aaa');
socket.io
-
服务端
const server = require('http').createServer(); const io = require('socket.io')(server); io.on('connection', client => { client.on('event', data => { /* … */ }); client.on('disconnect', () => { /* … */ }); console.log(client.handshake.query); client.emit("aaa","1111") // 设定事件 io.sockets.sockets // 所有客户对象 console.log(Array.from(io.sockets.sockets).map(item=>item[1].user)) }); server.listen(3000); -
客户端
// 前端使用之前先去下载socketio.js const socket = io(`ws://localhost:3000?token=${token}`); socket.on("aaa",(msg)=>{ // 触发事件 console.log(msg); })
Mocha
-
单元测试是用来对一个模块、一个函数或者一个类来进行正确性校验的测试工作
npm install mocha
。// package.json 预留直接npm test即可运行。 script:{ test:mocha, } // 你运行mocha后它会在当前文件夹下寻找test文件夹,并执行里面的所有文件。测试文件中可以划分测试组(describe)和测试(it) var assert = require("assert") // 断言 var { it } = require("mocha") describe("一个组",()=>{ it("一个测试",()=>{ assert.strictEqual(sum(1),1); }) }) -
chai断言,mocha允许你使用任意你喜欢的断岩库,我们使用nodejs的内置的断言模块,如果结果不匹配就会报错
npm install chai
。// top 1 var chai = require("chai"); var assert = chai.assert; describe("assert Demo",function(){ it("use assert lib", function(){ var value = "hello"; assert.typeOf(value,'string'); assert.equal(value,'hello'); assert.lengthOf(value,5); }) }) // top 2 var chai = require('chai'); chai.should(); describe('should Demo',function(){ it('use should lib',function(){ var value = 'hello'; value.should.exist.and.equal('hello').and.have.length(5).and.be.a('string'); }) }) // top 3 var chai = require("chai"); var expect = chai.expect; describe('expect Demo', function(){ it('use expect lib',function(){ var value = 'hello'; var number = 3; expect(number).to.be.at.most(5); expect(number).to.be.at.least(3); expect(number).to.be.within(1,4); expect(value).to.exist; expect(value).to.be.a('string'); expect(value).to.equal('hello'); expect(value).to.not.equal('你好'); expect(value).to.have.length(5); }) }) -
异步测试
var fs = require("fs").promises; var chai = require("chai"); var expect = chai.expect; it('test async function',async function (done){ const data = await fs.readFile("./1.txt",'utf8'); expect(data).to.equal("hello"); done(); // 等待测试 }) -
http测试
const request = require("supertest"); const app = require("../app"); describe("#test koa app",()=>{ let server = app.listen(3000); describe('#test server',()=>{ it("#test GET /", async()=>{ await request(server) .get('/') .expect("Content-Type",/text\/html/) .expect(200,'hello world'); }) after(function(){ server.close() }) }) }) -
钩子函数
describe("#hello.js",()=>{ describe("#sum()",()=>{ before(function(){ console.log("before:"); }); after(function(){ console.log("after."); }); beforeEach(function(){ consloe.log("befoeEach;") }); afterEach(function(){ console.log("afterEach.") }) }) })
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理