26.DOM
- DOM概念 将每一个标签/属性/文本/注释/元素,都看作是一个DOM元素/节点/对象(提供了一些操作元素的属性/方法) ==面试题== HTML/XHTML/DHTML/XML 分别是什么? 1、HTML - 网页 2、XHTML - 更严格的HTML,HTML5->XHTML->HTML4.01 3、DHTML - 动态的网页:D:Dynamic - 其实并不是新技术、新概念,是将现有技术的整合统称,让我们在离线时,网页也具有动态效果 DHTML:html+css+js(dom) 4、XML - 未知的标记语言,一切的标记由自己定义,数据格式
DOM原本是可以操作一切结构化文档的HTML和XML,后来为了方便各类开发者分为了3部分:
-
核心DOM:既可以操作HTML又可以操作XML
- 缺陷:API比较繁琐
-
HTML DOM:只能操作HTML,API简单
- 缺陷:比如属性部分,只能访问标准属性,不能访问自定义属性
-
XML DOM:只能操作XML(XML已经淘汰了,现在最流行的数据格式是JSON) 开发建议:优先使用HTML DOM,HTML DOM实现不了再用核心DOM进行补充
-
DOM树: 概念:DOM将我们的HTML看做了是一个倒挂的树状结构,但是树根不是html标签,而是document对象 document对象:不需要去创建,由浏览器的js解释器自动创建,一个页面只有一个document 作用:可以通过树根找到页面上的每一个DOM元素/节点/对象,也可以操作它
-
每个DOM元素都有三大属性:
- elem.nodeType:描述节点的类型
- document节点:9
- element节点:1
- attribute节点:2
- text节点:3
- 注:以前用于判断xx是不是一个页面元素(children不会得到文本节点的,但是以前的childNodes会得到文本节点)
- attrNode.nodeValue:描述节点的值
- 注:以前有用:先拿到属性节点,再用此属性去获取属性值
- ***elem.nodeName:描述节点的名字(e.target中也会用到)
- 作用:拿到当前元素的标签名,判断xx是什么标签
- 注:返回是一个全大写组成的标签名
- elem.nodeType:描述节点的类型
查找元素
-
通过关系查找元素: 前提条件:必须先找到一个元素才可以调用关系网
- 父元素:elem.parentNode;
- 子元素:elem.children; (找到的是一个子元素集合)
- 第一个儿子:elem.firstElementChild;
- 最后一个儿子:elem.lastElementChild;
- 前一个兄弟:elem.previousElementSibling;
- 后一个兄弟:elem.nextElementSibling;
-
递归:简单来说就是函数中,又一次调用了函数自己,迟早有一天会停下来
- 使用场景:遍历DOM树,专门用于【遍历层级不明确】的情况,既可以遍历层级不明确的DOM树,也可以遍历层级不明确的数据!
- 使用方法:2步 function 函数名(root){ 1、第一层要做什么直接做! 2、判断他有没有下一级,如果有下一级,再次调用此函数,但是传入的实参是他的下一级 } 函数名(实际的根)
- 算法:深度优先!优先遍历当前系欸但的子节点,子节点遍历完才会跳到兄弟节点
- 缺点:同时开启大量的函数调用,大量消耗内存,只有一个情况才用:【遍历层级不明确】
- 递归 vs 循环:
- 递归
- 优点:直观、易用
- 缺点:性能较低,尽量只在层级不明确的时候使用
- 循环
- 优点:几乎不占用内存
- 缺点:使用难度高
- 递归
-
TreeWalker(专门用于遍历层级不明确的DOM树的API)
- 使用方法:2步
- 先创建出tw: var tw=document.createTreeWalker(根元素,NodeFilter.SHOW_ALL/SHOW_ELEMENT);
- tw对象过后,反复调用nextNode方法找到下一个节点,迟早有一天会等于null,说明没找到,公式: while((node=tw.nextNode())!=null){node要干什么}
- 缺陷:
- 自动的跳过根元素,根元素是不会做任何操作的
- 仅仅只能遍历层级不明确的DOM树,不能遍历层级不明确的数据
- 使用方法:2步
-
API直接找元素:
- 根据HTML的特点去找元素
- 通过ID查找元素
- 语法:var elem=document.getElementById("id值");
- 特殊:
- 返回值,找到了返回的是一个当前找到的DOM元素;没找到,返回一个null,做了别的操作可能就会报错
- 找到了多个相同的id,那么只会返回第一个
- 一次只能获取一个元素,也只能操作一个元素
- 其实根本不需要使用此方法,直接写ID也可以找到元素
- 通过标签名查找元素
- 语法:var elems=document/已经找到了的父元素.getElementsByTagName("标签名");
- 特殊:
- 返回值:找到了返回的一个是==类数组==DOM集合(很像数组,都能用下标,都能用length,都能遍历),没找到返回一个空集合
- JS不能直接操作DOM集合,只能直接操作DOM元素,解决:要么使用下标拿到某一个元素,要么使用遍历拿到每一个元素
- 不一定非要从document开始查找,如果document去找,会找到所有的元素,可以换成我们已经找到的某个父元素,就只会找到这个父元素下面的元素了
- 通过class名查找元素
- 语法:var elems=document/已经找到了的父元素.getElementsByClassName("标签名");
- 通过Name查找元素
- 语法:var elems=document/已经找到了的父元素.getElementsByName("标签名");
- 通过ID查找元素
- 根据CSS选择器去找元素:
- 单个元素:
- 语法:var elem=document.querySelector("任意的css选择器");
- 强调:万一选择器匹配到多个,只会返回第一个,没找到返回null
- 多个元素:
- 语法:var elem=document.querySelectorAll("任意的css选择器");
- 强调:找到了返回集合,没找到返回空集合
- 单个元素:
- 根据HTML的特点去找元素
==面试题/笔试题==: getXXX 和 querySelectorAll 有什么区别? 返回结果不同的: 1、getXXX:返回的是要给动态集合HTMLCollection 优点:数据始终和DOM树实时挂钩 缺点:每次DOM树进行修改,都会悄悄的再次查找元素,效率相对较低 2、querySelectorAll:返回的是要给静态集合NodeList 优点:每次不会悄悄重新查找,效率较高,而且还支持使用forEach!
总结:找元素的方式:
- 直接查找元素:getXXX 和 querySelectorAll
- 通过关系找元素:
- 层级不明确的情况才用递归!
操作元素
前提:找到元素才能操作元素: <标签 属性名="属性值" style="样式">内容</标签> 强调:页面上获取/设置到的一切数据都是字符串类型
- 元素的内容:
- elem.innerHTML:获取/设置开始标签到结束标签之间的内容(支持识别标签,无兼容性问题)
- 获取:elem.innerHTML;
- 设置:elem.innerHTML="新内容";
- elem.textContent:获取/设置开始标签到结束标签之间的纯文本(不支持识别标签,有兼容性问题)
- 获取:elem.textContent;
- 设置:elem.textContent="新文本";
- 老IE:elem.innerText;(我们第一次见到小三上位)
- innerText某次浏览器更新后,现在主流浏览器也支持此属性
- 为什么老IE不将就主流?- 微软的,windows系统的使用的人多 以上两个属性都是为双标签准备的,但是操作不了单标签input的内容
- input.value:获取或设置表单控件的值(用于正则验证等场景)
- 获取:input.value;
- 设置:input.value="新值";
- elem.innerHTML:获取/设置开始标签到结束标签之间的内容(支持识别标签,无兼容性问题)
- 元素的属性:
- 获取属性值
- 核心DOM:elem.getAttribute("属性名");
- HTML DOM:elem.属性名;
- 设置属性值:
- 核心DOM:elem.setAttribute("属性名","属性值");
- HTML DOM:elem.属性名="属性值";
- 删除属性值:
- 核心DOM:elem.removeAttribute("属性名");
- HTML DOM:elem.属性名=""
- 删除不推荐使用HTML DOM,删除不干净属性节点,而有的属性,光有属性名就已经具有功能了
- 判断有没有属性(没用)
- 核心DOM:elem.hasAttribute("属性名")
- 仅仅只能判断有没有这个属性,不能判断出属性值是什么,往往我们自己用获取属性值的操作,获取到了过后再去进行比较运算
- HTML DOM:elem.属性名!="";
- 核心DOM:elem.hasAttribute("属性名")
- 缺陷:
- class必须写为className - 2015年过后,ES6诞生过后,class变成了一个关键字
- 不能操作自定义属性,只能操作标准属性
- 获取属性值
- 元素的样式
- 内联样式
- 优点:
- 仅仅当前元素可用,不会牵一发动全身
- 优先级最高,一定会覆盖其他的样式
- 获取:elem.style.css属性名;
- 设置:elem.style.css属性名="css属性值";
- 特殊:
- css属性名,有横线的地方,去掉横线,变为小驼峰命名法 如:border-radius -> borderRadius
- 缺陷:获取时,只能获取内联样式
- 优点:
- 样式表中的样式
- 找到你想要操作的样式表
- var sheet=document.styleSheets[i];
- 获取样式表中所有的样式规则
- var rules=sheet.cssRules;
- 找到自己想要操作的样式规则
- var rule=rules[i];
- 要么获取要么设置
- console.log(rule.style.css属性名);
- rule.style.css属性名="css属性值";
- 找到你想要操作的样式表
- 一切的获取都是为了判断;一切的设置都是修改或添加
- 绑定事件: elem.on事件名=function(){ 操作; } ==this==关键字:目前只能用于事件内: 如果单个元素绑定事件:this->这个元素 如果多个元素绑定事件:this->当前触发事件的元素
总结: 获取 - 往往都是用与判断比较 设置 - 就是添加/修改
创建元素并渲染DOM树
- 创建空标签:
- var 新元素=document.createElement("标签名");
- 为此标签设置必要的属性和事件
- 新元素.属性名="属性值";
- 新元素.on事件名=function(){操作}
- 把新元素上DOM树
- 父元素.appendChild(elem); - 将elem追加到父元素里当最后一个儿子
- 父元素.insertBefore(elem,已有子元素) - 将elem追加到父元素里,但是会插入在已有子元素的前面,缺点:会影响到其他元素的下标
- 父元素.replaceChild(elem,已有子元素) - 将elem追加到父元素里,但是会替换在已有子元素的
删除元素
elem.remove();
HTML DOM常用对象(简化核心DOM)
- image对象:仅仅只是简化了创建语句
- 创建:var img=new Image() === var elem=document.createElement("img");
- form对象:简化了查找元素
- 查找form元素:var form=document.forms[i];
- 查找form元素中的表单控件:var inp=form.elements[i];
- 专属事件:form.onsubmit=function(){return false;//阻止提交}//只在表单提交时触发的事件
- select对象:
- 属性:
- select.options;//得到select下面所有的option,完全等效于xx.children;
- select.selectedIndex;//得到当前选中项的下标,当时做二级(多级)联动就用到了他
- 方法:
- select.add(option);//完全等效于appendChild
- select.remove(i);//删除下标为i的option
- 专属事件:select.onchange=function(){//只有选中项发生变化了才会触发}
- 属性:
- option对象:仅仅只是简化了创建语句,但是非常牛逼
- 创建:var opt=new Option("innerHTML","value");
- 一句话完成四个操作:select.add(new Option("innerHTML","value"))
27.BOM
BOM概念: 提供专门用操作浏览器的一些对象(属性和方法),没有统一标准,存在兼容性问题,使用率相对较低
浏览器弹出框:
- 警告框:alert();
- 用户输入框:var user=prompt("提示文字","默认值");
- 用户确认框:var bool=confirm("提示文字");
定时器:
- 周期性定时器
- 开启 timer=setInterval(callback,间隔毫秒数)
- 停止 clearInterval(timer)
- 一次性定时器
- 开启 timer=setTimeout(callback,间隔毫秒数)
- 停止 clearTimeout(timer)
- 注意:一次性和周期性定时器底层相同,可以互换 ==面试题== 函数/循环/定时器都能反复执行操作,区别是什么? 时机:
- 函数=>用户触发、程序员调用
- 循环=>打开页面一瞬间基本就结束了
- 定时器=>等待一段时间就做一次
BOM对象:
- window对象-扮演两个角色
- 代替ES的global,充当全局对象,保存着全局变量和全局函数
- 自己也有方法和属性,指代当前窗口本身
- 属性:
- 获取浏览器的完整大小:outerWidth/outerHeight
- 获取浏览器的文档显示区域的大小:innerWidth/inerHeight
- 获取屏幕的完整大小screen.width/height
- 方法:
- 打开窗口:var newW=open('url','自定义的name','width=,height=,lefe=,top=')
- 注意:
- 第三个配置参数没有传入时,窗口大小与浏览器相同,并黏在浏览器上
- 写入第三个实参时,脱离浏览器成为独立的小窗口,可以保存用以绑定事件
- 宽高有最小限制
- 注意:
- 关闭窗口:window/newW.close()
- 修改窗口的大小:newW.resizeTo(宽,高)
- 修改窗口的位置:newW.moveTo(x,y)
- 打开窗口:var newW=open('url','自定义的name','width=,height=,lefe=,top=')
- 属性:
网页打开新链接的方式:4种(目的:提升用户体验感)
- 替换当前页面,可以后退
- HTML:<a href='url'>内容</a>
- JS:open('url','_self')
- 替换当前页面,禁止后退
- JS:location.replace('新url')
- 场景:电商网站用户付款后不允许退回再次付款
- 原理:
- history对象:记录着【当前窗口】的历史记录,只有有了历史才能前进后退
- location对象:记录着【当前窗口】正在打开的url,其replace方法是不会产生任何历史记录的,而url替换后网页必然跳转
- 新窗口打开,可以打开多个
- HTML:<a href='url' target='_blank'>内容</a>
- JS:open('url','__blank');
- 新窗口打开,只能打开一个
- HTML:<a href='#' target='自定义name'>内容</a>
- JS:open('url','自定义name');
- 场景:电商网站只允许用户打开一个付款页面
- 原理:每个窗口底层都有一个名字,target属性设置name值,如果name相同新窗口就会替换旧窗口
a标签的作用:
- 跳转
- 锚点
- 下载:<a href='xx.exe/压缩包后缀zip/rar/7z...'>内容</a>
- 打开:<a href='xx.图片后缀jpg/pgn.../txt'>内容</a>
- 直接书写JS:<a href='javascript:js代码'>内容</a>
- history对象
- 作用:保存当前窗口的历史记录(打开过的url)
- 方法:
- 前进: history.go(1)
- 后退: history.go(-1)
- 刷新: history.go(0)
- navigator对象
- 作用:保存了当前浏览器的基本信息,可以使用js来判断我们是什么浏览器以及版本号 - 类似css hack(专门准对老IE解决浏览器兼容问题),但更强大
- 属性:navigator.userAgent - 值为包含浏览器名和版本号的字符串,想办法格式化后针对不同浏览器写入对应的内容
- location对象
- 作用:保存当前窗口的url,location="新url"即可跳转
- url网址的组成部分:(5部分)协议名://域名:端口号/路由?请求消息
- 协议名:http、https、ftp、ws...
- 域名/主机号:底层都是主机号,域名需要购买
- 端口号:默认端口号可省略不写,https默认端口为443,http默认端口为80
- 文件相对路径/路由:决定用户看到哪个网页,可加密隐藏
- 查询字符串/请求消息:客户端发送到服务器端的内容,服务器端需要接收并判断请求内容,再进行相应
- 属性:
- 协议名:location.protocal
- 域名:location.hostname
- 端口号:location.port
- 路由:location.pathname
- 请求消息:location.search
- 方法:
- 跳转后禁止后退:location.replace('新url)
- 刷新:location.reload()
- event对象:事件对象
- 事件:用户触发或浏览器自动触发的
- 绑定事件:
- 在HTML页面绑定事件:
- <elem on事件名='js语句'>
- 缺点:
- 不符合内容/样式/行为分离的原则
- 无法动态绑定事件,一次只能绑定一个元素
- 无法同时绑定多个函数对象
- 在js中使用元素的事件处理函数属性:
- elem.on事件名=function(){操作}
- 优点:
- 符合分离原则
- 动态绑定事件
- 无兼容问题
- 缺点:
- 无法同时绑定多个函数对象(可以直接将多个功能写一起)
- 使用专门的事件API绑定事件
- 主流:elem.addEventListener('事件名',callback)
- 老IE:elem.attachEvent('on事件名',callback)
- 兼容:if(elem.addEventListener){ elem.addEventListener('事件名',callback) }else{ elem.attachEvent('on事件名',callback) }
- 优点:
- 符合分离原则
- 动态绑定事件
- 同时绑定多个对象
- 缺点:
- 存在兼容问题
- 在HTML页面绑定事件:
- 事件周期
- 主流:3个阶段
- 捕获阶段,记录着要发生的事件有哪些
- 目标元素(实际触发事件的元素)优先触发
- 冒泡触发,向上触发所有记录着的事件
- 老IE:2个阶段,没有捕获阶段
- 主流:3个阶段
- 获取事件对象event
- 主流:自动作为事件处理函数的第一个形参传入 - elem.on事件名=function(e){e->event}
- 老IE:event
- 兼容:var e=event(小三上位)
- 获取事件对象后可以做的操作
- 获取鼠标的坐标/位置(3种)
- e.screenX/Y - 获取鼠标相对于屏幕的位置
- e.clientX/Y - 获取鼠标相对于客户端/浏览器的位置
- e.pageX/Y - 获取鼠标相对于页面的位置
- 应用:鼠标跟随动画,思路:
- 鼠标移动事件window/document.onmousemove,添加图片元素,坐标设置为e.pageX/Y
- 因为js加载速度快于图片加载速度,在加载事件onload中,添加动画效果
- 动画开始时开启定时器删除图片元素
- 阻止冒泡 =笔试题=开发几乎不用
- 主流:e.stopPropagation()
- 老IE:e.cancelBubble=true
- 兼容:e.cancelBubble=true(小三上位)
- 事件委托/利用冒泡 =笔试题=开发也用
- 优化:如果对各子元素定义了相同或相似的事件,最好只给父元素定义一次
- 原因:每次绑定事件都创建了一个事件对象,创建的事件对象越多,网站性能越差
- this在事件中仅指向当前元素,在这里需要用到target(目标元素)
- 主流:e.target
- 老IE:e.srcElement
- 兼容:e.srcElement(小三上位)
- 阻止浏览器的默认行为(如a标签默认跳转页面、右键弹出菜单、F12控制台、F5刷新页面...)
- 主流:e.preventDefault();
- 老IE:e.returnValue=false;
- 兼容:e.returnValue=false;(小三上位)
- 新事件
- window.oncontextmenu=()=>{//鼠标右键事件}
- window.onkeydown=()=>{//键盘事件}
- 获取键盘的键码
- e.keyCode 不需要记忆,直接输出查看或搜索,再将其写入对应的条件判断语句
- 获取鼠标的坐标/位置(3种)
前言
全栈工程师:客户端(PC+移动端+小程序) + 服务器端(Node.js) + 数据库(mongoDB) 全栈晋升路线:全栈 -> 架构师 -> 项目经理 -> 技术总监 可能成为全栈的语言: 1、Java - 不包含移动端开发(能做安卓,不能做IOS) 2、JavaScript语言: 客户端 - 开发根本 服务器端 - Node.js 历史上第一次一门语言可以通吃前后端,前端崛起的原因之一 数据库 - mongoDB 移动端 - 网页、app、小程序 - 跨平台开发,只需要一个前端,学一点点Andriod和IOS的语法,就可以搞定了,前端崛起的原因之一 现在流行混合开发框架:uniapp/h5+plus/jQuery Mobile... 一个前端就可以搞定所有移动端了
sever服务器入门,搭配上ajax,完成最终目标=>全栈开发:登录、注册、后台管理系统
软件架构: C/S - Client客户端/Server服务器端 举例:QQ/大型网络游戏 优点: 运行稳定,用户体验感好,对带宽的要求低 缺点: 占用硬盘空间 更新过于麻烦,服务器端 和 客户端都要更新 B/S - Browser浏览器端/Server服务器端 举例: 网页版QQ、微信/网页游戏 优点: 几乎不占硬盘,不需要安装 更新只需要更新服务器端 缺点: 体验感较差(越来越好)- 云游戏(以后的趋势,不占用硬盘空间也无需相关硬件配置,全部交给云服务器计算),前端崛起的原因之一 现在5G时代的到来,对带宽的要求高
Node.js基础概念
Node.js是基于chrome的v8引擎的JavaScript运行环境 目的:形成了一个前端和数据库沟通交流的桥梁 - 数据交互 官网下载安装后,检验安装:cmd中输入node -v回车 检查版本号 运行方式:
- 交互模式 - 临时测试
- 打开cmd输入node回车 即可输入js代码
- 退出ctrl+c
- 脚本/文件模式 - 正式开发
- 创建xx.js 书写js代码
- 打开cmd输入node 文件绝对路径
- 编辑器中开发
- HBuilder 安装nodeeclipse插件
- VScode 安装Code Runner插件(注意修改配置文件,避免乱码)
js 与 node.js的异同:
- 相同点:都可以使用ECMAScript的一切语法/API
- 不同点:
- JavaScript包括DOM和BOM,用以做特效
- Node.js不支持DOM和BOM,有自己的模块
Node.js最大的特点:
- 快 - 以前最快的是php,Node.js的速度是php的14倍,异步能够更大的发挥node.js的特点
- 为什么快:
- 因为官方模块提供的东西少,甚至连数据库操作都没有
- 使用chrome的v8引擎
模块
- 定义:每一个.js文件都可以称为一个模块.分工合作开发时,将程序按功能分为不同模块再由不同的人完成,最后由主模块进行引入
- 模块公开/暴露自己的成员:
- exports.属性名=属性值
- module.exports={属性名:属性值...}
- 模块引入其他模块
- var xxx=require('./文件名')
- 注意:引入时./不可省略,文件后缀名可省略 ==笔试题==exports和module.exports的区别? 都可以用以公开暴露自己的成员,但exports={...}的写法是错误的,因为在Node.js的底层 exports=module.exports,真正做公开功能的时module.exports,如果使用exports={...}会覆盖module.exports,因此不再具有公开功能
- 模块的分类
- 官方模块
- 第三方模块 - npm下载
- 自定义模块
官方模块
不需要下载,在你安装node.js环境的时候就已经安好了,但是某的模块需要引入,某的模块不用引入,就需要学习看文档
- Globals模块:全局模块 -无需引入,全局可用
- __dirname:当前文件夹的绝对路径(用以相对路径无法使用的情况)
- __filename:当前文件的完整绝对路径
- exports:一个空对象,用以公开/暴露自己的成员
- require:一个函数,引领其他模块
- module:指代当前模块本身,包含其他四个变量
- 定时器
- 控制台
- Querystring模块:查询字符串
- 需要引入:const qs=require('querystring')
- 提供解析url查询字符串部分的功能
- var obj=qs.parse('查询字符串部分'),解析后可直接通过obj.键名获取对应部分
- 缺陷:只能解析查询字符串部分,无法解析完整url
- Url模块:网址
- 需要引入:const url=require('url)
- 提供解析完整url的函数
- var objUrl=url.parse('完整url',true)
- 此方法能将完整url网址的各个部分全部解析出来,支持传入第二个参数,如果传入的是一个true,自动调用Querystring的parse方法,顺便也解析了查询字符串
- 获取的重点:
- 请求消息:objUrl.query.键名 - 拿到前端传入后端的数据
- 路由:objUrl.pathname - 判断路由,响应不同网页
- Buffer模块:缓冲区,将数据转为16进制 - 无需引入,也无需主动使用
- 可以理解为Buffer是Node.js提供的一种新的数据类型
- Fs模块:filesystem 文件系统
- 需要引入:const fs=require('fs)
- 提供可以操作文件的API
- 异步读取文件:
- fs.readFile('绝对路径|文件路径',(err,buf)=>{需要执行的操作})
- 注意不可省略形参err只写形参buf
- 异步写入文件:(将原来的内容替换)
- fs.writeFile('绝对路径|文件路径','新写入的内容',(err,buf)=>{需要执行的操作})
- 异步追加文件:(保留原来的内容)
- fs.append('绝对路径|文件路径','新追加的内容',(err,buf)=>{需要执行的操作})
- http模块:使用代码搭建服务器
//引入http、url、fs官方模块
var http=require("http");
var url=require("url");
var fs=require("fs");
//创建服务器
var app=http.createServer();
//为服务器设置监听的端口号
app.listen(80);//http默认端口为80,https默认端口为443
//为服务器绑定请求事件 - 请求?前端发到后端的,
app.on("request",(req,res)=>{
//req - request:保存请求对象,请求对象,前端->后端,提供了一个属性req.url,解析此属性拿到自己需要的部分(路由|请求消息)
var objUrl=url.parse(req.url,true);
//得到前端传来路由部分
var router=objUrl.pathname;
//判断前端的路由是什么,给他返回不同的页面
if(router=="/" || router=="/index.html"){
//res - response:保存响应对象,后端->前端,提供了一个方法res.end(你想要响应的东西)
fs.readFile("./public/index.html",(err,buf)=>{
res.end(buf);
})
}else if(router.match(/html/)!=null){
console.log(router);
fs.readFile("./public"+router,(err,buf)=>{
res.end(buf);
})
}else if(router.match(/css|js|jpg|png|gif|woff/)!=null){
fs.readFile("./public"+router,(err,buf)=>{
res.end(buf);
})
}
})
强调:
- 前端的一切action、href、src,所有引入路径的地方,全都被node.js当作了是一个路由请求,解析请求,读取对应的文件给用户看
- 自己想要访问自己,打开浏览器,可以使用127.0.0.1访问自己,访问别人(前提:关闭防火墙),需要别人把自己的ipv4地址给你(打开cmd,输入ipconfig查看ipv4地址)
自定义模块
为什么有的模块要引入时加上./,有的模块又不需要?
- 文件模块:创建xx.js去公开需要公开的内容,主模块想要引入必须写为require("./文件名")
- 目录模块:3种
- 创建名为m1的文件夹,在其中创建index.js的文件,去需要公开的内容,主模块想要引入必须写为require("./文件夹的名字")
- 创建名为m2的文件夹,在其中创建xx.js的文件,去需要公开的内容,主模块想要引入必须写为require("./文件夹的名字") 但是需要在m2文件夹中,在创建一个必须package.json的配置文件
- 创建一个必须名为node_modules的文件夹,在其中创建名为m3的文件夹,在其中创建index/xx.js的文件,去需要公开的内容,主模块想要引入必须写为require("文件夹的名字")
其实真实开发中,我们程序员用的最多的就是文件模块,目录模块的第三种方式根本就不是人用的,是机器npm的使用的
第三方模块
npm:node package manager:node的模块/包管理器:专门管理第三方模块的,作用:下载安装、删除、更新、维护包的依赖关系... +如何使用第三方模块:
- 打开网站:npm官网
- 搜索你需要用到的模块,尽量用带有完全符合标志的那个包
- 打开cmd:检查一下npm下载工具是否安装成功:npm -v
- 下载:npm i 包名
- 删除:npm un 包名 - win7系统,删除时只需删除当前包,不会删除依赖关系
- 更新:npm up 包名 - 有可能此项目n年后要维护,有可能包就过期了,需要更新
数据库
数据库产品 - 放着很多很多和网站相关的数据
- 关系型数据库 - 以表格为主
- Oracle - Oracle(甲骨文) 主要应用于【企业级】开发市场,企业级:大公司、国企、事业单位(银行、警察局),不差钱的公司,安全性很高
- MySQL - Oracle(甲骨文) 主要应用于【互联网】开发市场,安全性相对较低,但是免费的,中小型公司的首选,但是和Node.js搭配不友好
- sql server - 微软:大学讲课
- 非关系型数据库 - 没有固定的格式,是一种运动 - 反关系型数据库
- 主流产品 - mongoDB,以JSON数据格式为主