node.js-获取网站标题 ## 前言 使用 node.js 获取网站得标题,使用的是 本地 的 http / https 模块 进入访问 目标网站,然后通过 cheerio 操作返回的DOM,就可以了 # 下载 cheerio 和 express ```nginx npm install cheerio express ``` # 引入包 ```javascript const express = require('express') // 引入处理 dom 模块 基于 jquery const cheerio = require('cheerio') const http = require('http') const https = require('https') ``` # 创建一个 app 并且监听 3000端口 ```javascript const app = express() app.listen(3000) ``` # 创建路由 ```javascript app.get('/get_title', (req, res) => { }) ``` # 接收传递过来的网站参数并且判断它是那种协议 ```javascript app.get('/get_title', (req, res) => { const url = req.query.url // 判断是否传递了 url if (!url) { res.send('请传递网站地址') return } const urlType = url.split(':')[0] == 'http' ? http : https }) ``` # 使用 http / https 模块进行发送请求 ```javascript let web = urlType.request(url, (result) => { let chunks = [] // 拼接请求片段数据 result.on('data', c => chunks.push(c)) // 拼接完成 result.on('end', () => { // 拼接所有的 chunks,并且转换为字符串 let data = Buffer.concat(chunks).toString('utf-8') // 使用 cheerio let $ = cheerio.load(data) // 获取到标题并且返回 res.send($('title').text()) }) }) //发送 web.end() ``` # 最后我们用一下 try catch 来处理一下错误信息 ```javascript try { let web = urlType.request(url, (result) => { let chunks = [] // 拼接请求片段数据 result.on('data', c => chunks.push(c)) // 拼接完成 result.on('end', () => { // 拼接所有的 chunks,并且转换为字符串 let data = Buffer.concat(chunks).toString('utf-8') let $ = cheerio.load(data) res.send($('title').text()) }) }) web.end() } catch { res.send('请正确的填写网站地址!') } ``` # 完整代码 ```javascript const express = require('express') // 引入处理 dom 模块 基于 jquery const cheerio = require('cheerio') const http = require('http') const https = require('https') const app = express() // 创建路由 app.get('/get_title', (req, res) => { const url = req.query.url // 判断是否传递了 url if (!url) { res.send('请传递网站地址') return } const urlType = url.split(':')[0] == 'http' ? http : https try { let web = urlType.request(url, (result) => { let chunks = [] // 拼接请求片段数据 result.on('data', c => chunks.push(c)) // 拼接完成 result.on('end', () => { // 拼接所有的 chunks,并且转换为字符串 let data = Buffer.concat(chunks).toString('utf-8') let $ = cheerio.load(data) res.send($('title').text()) }) }) web.end() } catch { res.send('请正确的填写网站地址!') } }) app.listen(3000) ```
后端
2021-06-07
138℃
0
6
node.js使用selenium-webdriver爬取画师通图片 # 前言: > 因为我昨天做了随机返回动漫图片的API,也去其他网站爬了一些动漫图片,大概有600多张感觉还是不够,然后就决定来爬一下画师通的图片了。 ## 技术选型 我使用的 node.js 来爬读,因为我是前端的麻,使用的包有 selenium-webdriver download image-size 注意:需要用到的 node.js npm 环境 自行部署 百度就可以找到 ------ # 1.我们先初始化一下项目 ```nginx npm init -y ``` # 2.创建文件 1. 创建 file 文件夹 存储下载好的图片 2. 创建 file.sql 存储图片信息的SQL语句 3. 创建 config.js 存储一下配置信息 4. 创建 main.js 作为 主函数 ### config.js 文件内容 ```javascript const obj = { // 需要爬的网站地址 URL: "https://www.huashi6.com/search?searchText=%E8%83%A1%E6%A1%83", // 生成的 SQL 语句存储的文件地址 fileSqlPage: './file.sql', // 图片的存储地址 fileImgPage: './file', // 图片地址的前叕 IMG_URL: 'http://api.xkbk.top/Anime/', // 表名 TABLENAME: 'Anime_imgs', // 图片名称的字段名称 IMGNAME: 'img_name', // 图片地址的字段名称 IMGURL: 'img_url', // 图片宽度的字段名称 width: 'width', // 图片高度的字段名称 height: 'height', // 开始扒的开始页码 currentPageNum: 1, // 结束页码 maxPageNum: 5, // 爬取页面是否存在分页 sliding: false, } module.exports = obj ``` # 3.我们先下载需要用的包 ```nginx npm install selenium-webdriver npm install download npm install image-size ``` # 4.下载对应的浏览器 exe 文件 地址:https://www.npmjs.com/package/selenium-webdriver 我用的是 火狐浏览器 因为 谷歌浏览器的包 它还没有 更新 ![](https://www.xkbk.top/uploads/20210607/c1fa4e5f7c78f982ae658b6720e001f5.png) 下载好了放在文件夹的根目录下载 ![](https://www.xkbk.top/uploads/20210607/422738bc2a87d9656cb25047223d66bc.png) # 5.把包引入 ```js // 操作浏览器 const { Builder, By, Key, until } = require('selenium-webdriver'); // 下载 const download = require('download') // 发送请求 const https = require('https') const path = require('path') const url = require('url') const fs = require('fs') // 获取图片信息 const sizeOf = require('image-size') ``` # 6.我们先创建一个打开浏览器的函数 ```javascript (async function example() { try { // 构建 firefox 浏览器 let driver = await new Builder().forBrowser('firefox').build(); // 判断爬取页面是否是需要滑动 if (config.sliding) { await driver.get(config.URL + '_' + currentPageNum); getData(driver) } else { await driver.get(config.URL); var p = 0; var item = setInterval(function () { driver.executeScript("window.scrollTo(50,document.body.scrollHeight)") p++ console.log(`当前在采集第${p}页`); if (p == maxPageNum - currentPageNum) { clearInterval(item) getData(driver) console.log('首页采集完毕,进入单页面访问并且下载!'); } }, 5000) } } finally { // 退出 // await driver.quit(); } })(); ``` # 7.创建一个处理数据的函数 ```javascript // 主函数 async function getData(driver) { // 获取每个图片卡片的地址 let items = await driver.findElements(By.css('.px-waterfall-item .px-img a')) // 卡片地址数组 let results = [] for (let i = 0; i < items.length; i++) { // 获取到 href let item = await items[i].getAttribute('href') // push 到 数组 results.push(item) }; // 图片地址 var img_url_list = [] for (let j = 0; j < results.length; j++) { let flag = true // 跳转到对应图片的页面 while (true) { try { console.log(`正在访问第${j + 1}张图片`); await driver.get(results[j]); // 获取到对应的元素 let img_url = await driver.findElement(By.css('.c-work-img .v-lazy-image')) // 获取到src let url = await img_url.getAttribute('src') // push img_url_list.push(url) if (results.length == j) { flag = false } } catch { if (e) { flag = false } } finally { if (flag) { break; } } } } console.log('开始下载'); // 每页下载数量初始值 var k = 0; // 将获取到的图片进行下载 Promise.all(img_url_list.map(async x => { let flag = true // 跳转到对应图片的页面 while (true) { try { // 进行下载 第一个 参数是下载地址 第二个是保存的地址 const dom = await download(x, config.fileImgPage) // 判断是否下载成功 if (!dom) { console.log(`下载失败数量:${k}`); } else { const imgUrl = x const options = url.parse(imgUrl) // 利用图片的地址发送请求获取到图片的信息 https.get(options, function (response) { const chunks = [] response.on('data', function (chunk) { chunks.push(chunk) }).on('end', function () { const buffer = Buffer.concat(chunks) let img_info = sizeOf(buffer) var str = x.split('?')[0] // 截取字符 获取到 图片的名字 var img_name = str.substr(52) var img_url = config.IMG_URL + img_name let data = `insert into ${config.TABLENAME} (${config.IMGNAME},${config.IMGURL},${config.width},${config.height}) values('${img_name}','${img_url}','${img_info.width}','${img_info.height}');\n` fs.appendFile(file, data, { encoding: 'utf8' }, err => { }) k++ console.log(`下载成功数量:${k}`); }) }) if (img_url_list.length == k) { flag = false } } } catch (e) { if (e) { flag = false } } finally { if (flag) { break; } } } })) .then(async () => { console.log(`第${currentPageNum}页下载完成!`); currentPageNum++ if (currentPageNum <= maxPageNum) { console.log('下载完毕'); await driver.get(config.URL + '_' + currentPageNum); getData(driver) } }) } ``` # 运行 ```nginx node main.js // 记得切换到项目根目录再运行 ``` ![](https://www.xkbk.top/uploads/20210607/692d09b29ea18e13f02821c05e815021.png) 完美下载。 码云:https://gitee.com/qq8575/node_selenium-webdriver 注意:只能爬读取画师通有分页的页面,没有分页的只能爬读第一页的20张图片,不能自动滑动。 如果有什么不明白的请留言,或者到[哔哩哔哩](https://space.bilibili.com/482322981)私信我
2021-06-07
92℃
0
0
tp5-editor.md--使用上传文件没有回显url 问题 ## editor.md 上传文件成功但是它没有回显URL 主要问题就是你返回的格式不正确,它要求的返回格式是一个空格存在都不允许,昨晚我就是搞了一晚上,没搞懂!今天早上一看好像多了一个空格,删了,就TM解决了。。 官方要求的返回格式 ```json { success : 0 | 1, // 0 表示上传失败,1 表示上传成功 message : "提示的信息,上传成功或上传失败及错误信息等。", url : "图片地址" // 上传成功时才返回 } ``` 还有就是你后端接收的表单 name 有可能出错了 官方这里的表单 name 是 editormd-image-file ## 具体代码 **前端** ```javascript var editor = editormd("write_post_main_content", { watch: false, // width : "100%", // height : "100%", path: "/static/admin/lib/editor.md-master/lib/", width: "100%", height: '400px', // theme: "dark", // previewTheme: "dark", // editorTheme: "pastel-on-dark", markdown: "", codeFold: true, //syncScrolling : false, saveHTMLToTextarea: true, // 保存 HTML 到 Textarea searchReplace: true, //watch : false, // 关闭实时预览 htmlDecode: "style,script,iframe|on*", // 开启 HTML 标签解析,为了安全性,默认不开启 // toolbar: false, //关闭工具栏 //previewCodeHighlight : false, // 关闭预览 HTML 的代码块高亮,默认开启 emoji: true, taskList: true, tocm: true, // Using [TOCM] tex: true, // 开启科学公式TeX语言支持,默认关闭 flowChart: true, // 开启流程图支持,默认关闭 sequenceDiagram: true, // 开启时序/序列图支持,默认关闭, toolbarIcons: function () { // Or return editormd.toolbarModes[name]; // full, simple, mini // Using "||" set icons align right. return ["undo", "redo", "|", "bold", "hr",'image', "|", "watch", "|", "fullscreen", "info", "testIcon", "testIcon2", "file", "faicon", "||", "watch", "testIcon"] }, // saveHTMLToTextarea : true, imageUpload : true, imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"], imageUploadURL : "/admin/Upload/index", }); ``` PHP(框架TP5) ```PHP <?php namespace app\admin\controller; use think\Controller; use think\facade\Request; class Upload extends Controller { public function index(){ if(request()->isPost()) { // 获取上传的文件 image 表单 name 名 $file = Request::file('editormd-image-file'); // 文件存储位置 $info = $file->move('../public/uploads'); // 判断上传信息 if ($info) { // return json([ 'success' => 1, 'message' => '上传成功!', 'url' => str_replace('\\', '/', Request::domain() . '/uploads/' . $info->getSaveName()) ]); } else { // 上传失败获取错误信息 echo $file->getError(); } } else { return '非法请求!'; } } } ```
后端
2021-06-07
68℃
0
0
VScode插件推荐,开发效率更高 > 下面推荐的插件都是我本人在用的插件,非常好用强烈推荐。 **1.Chinese (Simplified) Language Pack for Visual Studio Code** > 这是一款用来汉化VScode的如果你英文很好,可以选择不安装 **2.Easy LESS** > Easy LESS 是可以把 less 语法的 直接转换成 CSS ,保存文件就自动生成 **3.open in browser** > open in browser 是一款右键就可以把当前文件用浏览器打开,前提是该文件正常浏览器打开 ![](https://www.xkbk.top/uploads/20210607/30252615e9aa4c2fff7b3b7ef75c5900.png) **4.vscode-incon** > vscode-incon 是可以给 vscode 添加 各种文件图标,看起来还是很好看的 ![](https://www.xkbk.top/uploads/20210607/8fe133cb46d926d9269b33b566df513f.png) **5.Auto Rename Tag** > 是可以自动修改 标签的结束标签,按照 头来修改 ![](https://www.xkbk.top/uploads/20210607/44a7002f9224252271c288f0057442bb.gif) 我正在使用的插件就这么多。
2021-06-07
101℃
0
0
CSS波浪 波浪是用了SVG来做的,CSS部分还是挺简单的, ![](https://www.xkbk.top/uploads/20210607/41a637c2faa37a411fd2dddef8b0cbd6.gif) 代码如下 **HTML** ```HTML <!-- 头部盒子 --> <div class="header"> <!-- 标题区域 --> <div class="lnner-header"> <h1>CSS波浪</h1> </div> <!-- 波浪区域 --> <div> <!-- svg 形状 --> <svg class="waves" viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto"> <!-- 形状容器 --> <defs> <path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" /> </defs> <!-- 组合形状 --> <g class="parallax"> <use xlink:href="#gentle-wave" x="48" y="0" fill="rgba(255,255,255,0.7" /> <use xlink:href="#gentle-wave" x="48" y="3" fill="rgba(255,255,255,0.5)" /> <use xlink:href="#gentle-wave" x="48" y="5" fill="rgba(255,255,255,0.3)" /> <use xlink:href="#gentle-wave" x="48" y="7" fill="#fff" /> </g> </svg> </div> </div> ``` **CSS** ``` CSS body { margin: 0; } h1 { font-family: 'Lato','sans-serif'; font-weight: 300; /* font-spacing:2px; */ font-size: 48px; } .header { position: relative; text-align: center; /* 背景渐变 */ background: linear-gradient(60deg,rgba(84,58,183,1) 0%, rgba(0,172,193,1) 100%); color: wheat; } .lnner-header { height: 65vh; width: 100%; margin: 0; padding: 0; /* flex */ /* 垂直居中 */ display: flex; justify-content: center; align-items: center; } .waves { position: relative; width: 100%; height: 15vh; margin-bottom: -7px; /* 最小值 */ min-height: 100px; /* 最大值 */ max-height: 150px; } .parallax>use { animation: move-forever 25s cubic-bezier(.55,.5,.45,.5) infinite; } /* 选择的一个use */ .parallax>use:nth-child(1) { /* 延迟 2s 执行 */ animation-delay: -2s; /* 7s 内 执行完毕 */ animation-duration: 7s; } .parallax>use:nth-child(2) { animation-delay: -3s; animation-duration: 10s; } .parallax>use:nth-child(3) { animation-delay: -4s; animation-duration: 13s; } .parallax>use:nth-child(4) { animation-delay: -5s; animation-duration: 20s; } /* 动画 */ @keyframes move-forever { 0% { transform: translate3d(-90px,0,0); } 100% { transform: translate3d(85px,0,0); } } /* 当屏幕小于 768px 执行 */ @media (max-width : 768px) { .waves { height: 40px; min-height: 40px; } h1 { font-size: 24px; } } ```
前端
2021-06-07
127℃
0
0
node.js使用Sequelize操作mysql # node.js使用Sequelize操作mysql ## 1.安装 ```nginx npm install --save sequelize npm install --save mysql2 ``` ## 2.连接数据库 ```javascript const Sequelize = require('sequelize'); const sequelize = new Sequelize('test', 'root', '658575', { host: 'localhost', dialect: 'mysql', port:'3306' }) sequelize .authenticate() .then(() => { console.log('连接成功'); }) .catch(err => { console.error('Unable to connect to the database:'); }); ``` ## 3.创建模型 ### 表约束 - timestamps:是否给每条记录添加 createdAt 和 updatedAt 字段,并在添加新数据和更新数据的时候自动设置这两个字段的值,默认为true - paranoid:设置 deletedAt 字段,当删除一条记录的时候,并不是真的销毁记录,而是通过该字段来标示,即保留数据,进行假删除,默认为false - freezeTableName:禁用修改表名; 默认情况下,sequelize将自动将所有传递的模型名称(define的第一个参数)转换为复数。 默认为false - tableName:手动设置表的实际名称 - 定义表索引 indexes:Array<Object> ### 字段约束 - type:字段类型,String|DataTypes - allowNull:是否允许为空,默认为true - defaultValue:默认值,默认为null - unique:值唯一,默认为false - primaryKey:是否为主键,默认为false ```java // 导入创建模型需要的函数 const { Sequelize, sequelize } = require('../init') // 创建模式 第一个参数是 表名 const User = sequelize.define('user', { // 一个对象就是一个字段 username: { // 约束字段的类型 type: Sequelize.STRING, // 是否允许为空 默认是 true allowNull: false, }, password: { type: Sequelize.STRING, // 是否允许为空 默认是 true allowNull:false } }) ``` ### 4.查询数据 ```javascript // 查找所有用户 User.findAll().then(users => { // 转换为 json 字符串 console.log("All users:", JSON.stringify(users, null, 4)); }); ``` ### 5.创建用户 ```javascript // 创建新用户 // 创建成功返回 用户对象 User.create({ username: "admin", password:"123456"}).then(user => { console.log('创建成功!'+ user.username); }); ``` ### 6.修改用户信息 ```javascript // 将所有 password 为 123456 User.update({ password: "123456" }, { where: { password: '' } }).then(() => { console.log("修改成功"); }); ``` ### 7.删除用户 ```javascript // 删除所有名为“admin”的人 User.destroy({ where: { username: 'admin' } }).then(() => { console.log("删除所有名为admin的用户成功"); }); ```
后端
2021-06-07
61℃
1
0
node.js 发送邮件 # node.js 发送邮件 > 下载 nodemailer 模块 来发送邮件 ```nginx npm install nodemailer ``` 引入 nodemailer 模块: ```javascript const nodemailer = require('nodemailer') ``` 配置邮箱信息 ```js var transporter = nodemailer.createTransport({ host: smtp.qq.com, // 端口 port: 465, // 开启安全连接 secureConnection: true, secure: true, // 发件人配置 auth: { // 邮箱账号 user: "", // 授权码 pass: "" }, }) ``` 配置发送信息 ```javascript // 发送内容 var mailOptios = { // 发件人邮箱 from: "", // 收件人邮箱 to: "", // 邮件主题 subject: 'XIAOKE图床邮箱验证', // 内容 // text: "测试邮件" html: ` <h1>尊敬的用户<h1/> <p>您刚刚在<span style="color:red;">XIAOKE图床</span>提出账号注册申请验证</p> <p>你的验证码是:<span style="color:red;">${emailobj.Verification}</span> </p> <p>验证码有效期:<span style="color:red;">2分钟</span></p> <div style="text-align: right;"> <p>如果不是您主动注册或操作,请无视本邮件即可!</p> <p>感谢您的访问,祝您访问愉快,系统邮件请勿回复!</p> <p>——来自<span style="color:red;">XIAOKE图床</span></p> </div> ` } ``` 发送 ```JavaScript // 发送 transporter.sendMail(mailOptios, (err, info) => { if (err) { console.log('发送失败!') return } console.log('发送成功!') }) ```
后端
2021-06-07
58℃
0
0
node跨域解决方案 ## 同源政策 #### 什么是同源? > 如果两个页面拥有相同的协议,域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。 #### 同源政策的目的 > 同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据,最初的同源政策是指A网站在客户端设置的cookie,B网站是不能访问的。 > > 随着互联网的发展,同源政策也越来越严格了,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax请求,如果有请求浏览器就会报错 #### 使用JSONP 解决同源限制问题 > jsonp 是 json with padding 的缩写,它不属于Ajax请求,但它可以模拟Ajax请求 1. 将不同源的服务器端请求地址写在script标签的src属性中 ```javascript <script src="http://localhost:3001/test"></script> ``` 2. 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要找我函数调用的参数 ```javascript var data = 'fn({name: "xiaoke" , age: "16" })' res.send(data) ``` 3. 在客户端全局作用域下定义函数 fn ```javascript function fn (data) {} ``` 4. 在 fn 函数内部对服务器端返回的数据进行处理 ```javascript function fn (data) { console.log(data) } ``` #### CORS 跨域资源共享 > CORS:全称为 Cross-origin resource sharing 即跨域资源共享,它允许浏览器向跨域服务器发送Ajax请求,克服了Ajax 只能同源使用的限制 ```javascript origin: http://localhost:3000 ``` ##### 服务器端代码 ```javascript // 所有express框架得中间件 拦截所有的请求 // 拦截所有请求 app.use('*',function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); //这个表示任意域名都可以访问,这样写不能携带cookie了。 //res.header('Access-Control-Allow-Origin', 'http://www.baidu.com'); //这样写,只有www.baidu.com 可以访问。 res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild'); res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');//设置方法 if (req.method == 'OPTIONS') { res.send(200); // 意思是,在正常的请求之前,会发送一个验证,是否可以请求。 } else { next(); } }); ```
后端
2021-06-07
77℃
0
0
Ajax笔记 # Ajax基础 ## Ajax概况 > 它是浏览器提供的一套方法,可以实现页面无刷新更新网站数据,提高用户浏览网站应用体验 > ## Ajax 应用场景 1. 页面上拉加载更多数据 2. 列表数据无刷新分页 3. 表单项离开焦点后验证 4. 搜索框提示文字下拉列表 ## Ajax 的运行环境 > AJax 技术需要运行在网站服务器中才能生效 使用 node 创建网站服务器 ## Ajax运行原理 Ajax 相当于浏览器发送请求与接收响应的代理人, 以实现在不影响用户浏览页面的情况下,局部更新页面数据,从而提高用户的体验 ## Ajax 实现步骤 1.创建 Ajax 对象 ```javascript var xhr = new XHLHttpRequest(); ``` 2.告诉 Ajax 请求地址以及请求方式 ```javascript xhr.open( 'get' , ' 请求地址 ' ) ``` 3.发送请求 ```javascript xhr.send() ``` 4.获取服务器端给与客户端的响应数据 ```javascript xhr.onload = function () { console.log( xhr.responseText ) } ``` ```javascript // 1.创建Ajax 对象 var xhr = new XMLHttpRequest(); // 2. 告诉 Ajax 请求方式以及请求地址 xhr.open('get', 'http://localhost/first') // 3.发送请求 xhr.send() // 4.获取服务器端给与客户端的响应数据 xhr.onload = function () { // xhr.responseText console.log(xhr.responseText) } ``` ## 请求参数传递 ### GET请求方法 ```javascript <p> <input type="text" placeholder="请输入名称"> </p> <p> <input type="text" placeholder="年龄"> </p> <p> <input type="button" value="提交" id="btn"> </p> <script> // 获取元素 var btn = document.querySelector('#btn') var text = document.querySelectorAll('input') // 添加点击事件 btn.onclick = function () { // 创建Ajax 对象 var xhr = new XMLHttpRequest(); // 获取文本框 输入的值 var name = text[0].value var age = text[1].value // 拼接请求参数 var params = 'name=' + name + '&age=' + age // 告诉 Ajax 请求方式以及请求地址 xhr.open('get', 'http://localhost/get?' + params) // 发送请求 xhr.send() // 获取服务器端给与客户端的响应数据 xhr.onload = function () { var responseText = JSON.parse(xhr.responseText) console.log(responseText); } } </script> ``` ### POST请求方法 ```javascript <p> <input type="text" placeholder="请输入名称"> </p> <p> <input type="text" placeholder="年龄"> </p> <p> <input type="button" value="提交" id="btn"> </p> <script> // 获取元素 var btn = document.querySelector('#btn') var text = document.querySelectorAll('input') // 添加点击事件 btn.onclick = function () { // 创建Ajax 对象 var xhr = new XMLHttpRequest(); // 获取文本框 输入的值 var name = text[0].value var age = text[1].value // 拼接请求参数 var params = 'name=' + name + '&age=' + age // 告诉 Ajax 请求方式以及请求地址 xhr.open('post', 'http://localhost/post') // 请求参数的格式类型(post请求 必须要设置) xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') // post请求的参数在xhr.send() 方法里面 xhr.send(params) // 获取服务器端给与客户端的响应数据 xhr.onload = function () { var responseText = JSON.parse(xhr.responseText) console.log(responseText); } } </script> ``` ## 获取服务端的响应(了解) ### Ajax 状态码 > 在创建Ajax对象,配置Ajax对象,发送请求,以及接收完服务端响应数据,这个过程的每一个步骤都会对应一个数值,这个数值就是Ajax状态码 ​ 0: 请求未初始化( 还没有调用 open() ) ​ 1: 请求已经建立,都是还没有发送( 还没有调用 send() ) ​ 2: 请求已经发送 ​ 3: 请求正在处理中,通常响应中已经有部分数据可以用了 ​ 4: 响应已经完成,可以获取并使用服务器的响应了 ```javascript // 获取状态码 xhr.onreadystatechange = function () { console.log(xhr.readyState); } ``` ## Ajax错误处理 ​ 1. 网络畅通,服务器端能接收到请求,服务器端返回的结果不是预期的结果 > 可以判断服务器端返回的状态码,分别进行处理,xhr.status 获取http状态码 2. 网络畅通,服务器端没有收到请求,返回状态码 404 > 检查请求地址是否错误 3. 网络畅通,服务器端能接收到请求,服务器端返回500状态码 > 服务器端错误,后端错误 4.网络中断,请求无法发送到服务器端 > 会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理 ## 低版本 IE浏览器的缓存问题 > 问题:在低版本 IE浏览器中,Ajax请求有严重的缓存问题,即在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务器端,后续的请求都会从浏览器的缓存中获取结果,即使服务器端数据更新了,客户端依然拿到的是缓存中的旧数据 > 解决方案: 在请求地址的后面加请求参数,保证每一次请求中的请求参数的值不相同 ```javascript xhr.open('get','http://xkbk.top?t=' + Math.random() ) ``` ## 同步异步概述 ### 同步 - 一个人同一时间只能做一件事情,只有一件事情做完,才能做另外一件事 - 落实到代码中,就是上一行代码执行完成,才能执行下一行代码,即逐行执行代码 ```javascript console.log('1') console.log('2') ``` ### 异步 - 一个人一件事情做到一半,转而去做其他事情,当其他事情做完以后,再回过头来继续做之前未完成的事情 - 落实到代码中,就是异步代码虽然需要花费时间去执行,但程序不会等待异步代码执行完成后再继续执行后续代码,而是直接执行后续代码,当后续代码执行完成后再回头看异步代码是否返结果,如果已有返回结果,再调用事先准备好的回调函数处理异步代码执行结果 ```javascript console.log('pink') setTimeout( () => { console.log('blue') },2000) ``` ## Ajax 封装 问题:发送一次请求代码过多,发送多次请求代码重复过多 解决方案:将请求代码封装到函数中,发送请求时调用函数即可。 ## 模板引擎 > 作用:使用模板引擎提供的模板语法,可以将数据和HTML拼接起来 > > 官方地址:http://aui.github.io/art-template/zh-cn/index.html ### 使用步骤 1. 下载art-template模板引擎文件并在HTML页面中引入库文件 ```javascript <script src="./js/template-web.js"></script> ``` 2. 准备atr-template模板 ```javascript <script id="tp1" type="text/html"> <div class="box"> </div> </script> ``` 3. 告诉模板引擎将哪一个模板和哪一个数据进行拼接 ```javascript // 第一个参数是 模板id 第二个参数是数据 var html = template('tp1',{ username:'xiaoke', age:'17' }) ``` 4. 将拼接好的html字符串添加到页面中 ```javascript document.getElementById('container').innerHTML = html ``` 5. 通过模板语法告诉模板引擎,数据和html字符串要如何拼接 ```javascript <script id="tp1" type="text/html"> <div class="box"> {{ username }} </div> </script> ``` ## formData 对象的作用 > 配合node 使用formidable模块 - 模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式 1. 准备好HTML表单 ```html <form id="form"> <input type="text" name="username"> <input type="password" name="password"> <input type="button" value=""> </form> ``` 2. 将HTML表单转换为 formData对象 ```javascript var form = document.querySelector("#form") var formData = new FormData(form) ``` 3. 提交表单 ```javascript xhr.send(formData) ``` - 异步上传二进制文件 ## formData 对象的实例子方法 1. 获取表单对象中的属性值 ```javascript formData.get('key') ``` 2. 设置表单对象属性的值 ```javascript formData.set('key','value') ``` 3. 删除表单对象中的属性值 ```javascript formData.delete('key') ``` 4. 向表单对象中追加属性值 ```javascript formData.append('key','value') ``` > 注意:set 方法与 append 方法的区别是,在属性名已存在的情况下,set 会覆盖已有的键名的值, append会保留两个值 ## formData 文件上传图片即时预览 > 在我们将图片上传到服务器端以后,服务器端通常都会将图片地址做为响应数据传递到客户端,客户端可以从响应数据中获取图片地址,如何将图片再显示在页面中 服务器端代码 ```javascript // 实现文件上传路由 app.post('/upload', (req, res) => { // 创建formidable表单解析对象 var form = new formidable.IncomingForm() // 设置客户端文件上传的存储路径 form.uploadDir = path.join(__dirname, 'public', 'upload') // 保留上传文件的后缀名 form.keepExtensions = true // 解析客户端传递过来的FormData对象 form.parse(req, (err, fields, files) => { res.send({ path: files.attrName.path.split('public')[1] }) }) // res.send('ok') }) ``` 客户端代码 ```javascript xhr.onload = function () { if (xhr.status == 200) { var result = JSON.parse(xhr.responseText) // 上传文件夹即时预览 // 动态创建img var img = document.createElement('img') // 给图片设置src属性 img.src = result.path // 添加到页面中 img.onload = function () { box.appendChild(img) } } } ``` ## Ajax 请求限制 Ajax 只能向自己的服务器发送请求。比如现在有一个A网站,有一个B网站,A网站中的HTML文件只能向A网站服务器发送Ajax请求,B网站中的HTML文件只能向B网站中发送Ajax请求,都是A网站是不能向B网站发送Ajax请求的,同理,B网站也不能向A网站发送Ajax请求。 ## 同源政策 #### 什么是同源? > 如果两个页面拥有相同的协议,域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。 #### 同源政策的目的 > 同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据,最初的同源政策是指A网站在客户端设置的cookie,B网站是不能访问的。 > > 随着互联网的发展,同源政策也越来越严格了,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax请求,如果有请求浏览器就会报错 #### 使用JSONP 解决同源限制问题 > jsonp 是 json with padding 的缩写,它不属于Ajax请求,但它可以模拟Ajax请求 1. 将不同源的服务器端请求地址写在script标签的src属性中 ```javascript <script src="http://localhost:3001/test"></script> ``` 2. 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要找我函数调用的参数 ```javascript var data = 'fn({name: "xiaoke" , age: "16" })' res.send(data) ``` 3. 在客户端全局作用域下定义函数 fn ```javascript function fn (data) {} ``` 4. 在 fn 函数内部对服务器端返回的数据进行处理 ```javascript function fn (data) { console.log(data) } ``` #### JSONP 代码优化 1. 客户端需要将函数名称传递到服务器端 2. 将script请求的发送变成动态请求。 3. 设置请求成功后执行的回调函数 4. 设置传递参数 #### 服务器代码优化 > 可以直接返回JSON数据 ```javascript res.jsonp({ name: "xioake", age: 16 }) ``` #### CORS 跨域资源共享 > CORS:全称为 Cross-origin resource sharing 即跨域资源共享,它允许浏览器向跨域服务器发送Ajax请求,克服了Ajax 只能同源使用的限制 ```javascript origin: http://localhost:3000 ``` ##### 服务器端代码 ```javascript // 所有express框架得中间件 拦截所有的请求 // 拦截所有请求 app.use((req,res,next) => { // 1.允许那些客户端访问我 res.header('Access-Control-Allow-Origin','*') // * 是允许使用人访问 // 2.允许客户端使用那些请求方法访问我 多个请求使用 , 来分开 res.header('Access-Control-Allow-Methods', 'get,post') next() }) ``` #### 访问非同源数据 服务器端解决方案 > 同源政策是浏览器给予 Ajax 技术的限制 服务器端是不存在同源政策限制 > 使用node中的第三方模块 request #### get请求 ```javascript request({ timeout:5000, // 设置超时 method:'GET', //请求方式 url:'', //url qs:{ //参数,注意get和post的参数设置不一样 xxx:"xxx", xxx:"xxx" } },function (error, response, body) { if (!error && response.statusCode == 200) { console.log(body); res.send(body) }else{ console.log("error"); } }); ``` #### post请求 ```javascript    request({ timeout:5000, // 设置超时 method:'GET', //请求方式 url:'xxx', //url form:{ //参数,注意get和post的参数设置不一样 xx:"xxx", xxx:"xxx", xxx:"xxx" } },function (error, response, body) { if (!error && response.statusCode == 200) { console.log(body); }else{ console.log("error"); } ``` #### withCredentials属性 > 在使用Ajax请求技术发送跨域请求时,默认情况下不会在请求中携带cookie信息 > > withCredentials:指定这涉及到跨域请求时,是否携带cookie信息,默认值为false > > Access-Control-Allow-Credentials:true 允许客户端发送请求携带cookie ```javascript // 允许客户端发送跨域请求时携带cookie信息 res.header('Access-Control-Allow-Creden tials', true); ``` # XML基础 ### XML是什么 XML的全称是 extensible markup language 代表可扩展标记语言 它的作用是传输和存储数据 ```xml /* 实例代码 */ <students> <student> <sid>001</sid> <name>小白</name> </student> <studend> <sid>002</sid> <name>二狗子</name> </studend> </students> ``` ### XML DOM XML DOM 即 XML 文档对象模型,是w3c 组织定义的一套操作 XML 文档对象的 API 浏览器会将 XML 文档解析成文档对象模型
笔记
2021-06-07
96℃
0
0
Canvas笔记 # Canvas > HTML5 <canvas> 标签是用于绘制图像 ( 通过脚本,通常是 JavaScript ) > > 不过, <canvas> 元素本身并没有绘制能力(它仅仅是一个容器)必须使用脚本来实际的绘图任务 > > getContext() 它返回一个对象,该对象提供了用于在画布上绘图的方法和属性 > > 提供完整的 getContext( "2d" ) 对象的属性和方法 可用于在画布是绘制文本,线条,矩形,圆形,等等 > > canvas 三要素: > > id: 唯一标识 > > width: 画布内容的宽度的像素大小 (与 style 的宽度和高度是有区别的) > > height: 画布内容的高度的像素大小 > > **注意**:canvas 仅仅是一个容器需要绘制内容,需要用js来绘制 ## 颜色 | 属性 | 描述 | | ------------- | ---------------------------------------- | | fillStyle | 设置或返回用于填充绘画的颜色,渐变或模式 | | strokeStyle | 设置或返回用于笔触的颜色,渐变或模式 | | shadowColor | 设置或返回用于阴影的颜色 | | shadowBlur | 设置或返回用于阴影的模糊级别 | | shadowOffsetX | 设置或返回阴影与形状的水平距离 | | shadowOffsetY | 设置或返回阴影与形状的垂直距离 | | 方法 | 描述 | | ---------------------- | ------------------------------------------ | | createLinearGradient() | 创建线性渐变(用于在画布内容上) | | createPattern() | 在指定的方向上重复指定的元素 | | createRadialGradient() | 创建放射状/环形的渐变 ( 用于在画布内容上 ) | | addColorStop() | 规定渐变对象中的颜色和停止位置 | ## 线条样式 | 属性 | 描述 | | ---------- | ------------------------------------------------------------ | | lineCap | 设置或返回线条的结束端点样式 ( 默认是默认是 butt 是平直角 圆角 round ) | | lineJoin | 设置或返回两条线相交时,所创建的拐角类型 ( 默认的是 mi ) | | lineWidth | 设置或返回当然线条的宽度 | | miterLimit | 设置或返回最大斜接长度 | ## 矩形 | 方法 | 描述 | | ------------ | ---------------------------- | | rect() | 创建矩形 | | fillRect() | 绘制 "被填充" 的矩形 | | strokeRech() | 绘制矩形 ( 无填充 ) | | clearRech() | 在给定的矩形内清除指定的像素 | ## 路径 | 方法 | 描述 | | ------------------ | ------------------------------------------------------ | | fill() | 填充当前绘图 ( 路径 ) | | strkoe() | 绘制已定义的路径 | | beginPath() | 起始一条路径,或重置当前路径 | | moveTo() | 把路径移动到画布中的指定点,不创建线条 | | closePath() | 创建从当前点回到起始点的路径 | | lineTo() | 添加一个新点,然后在画布中创建从 | | clip() | 从原始画布剪切任意形状和尺寸的区域 | | quadraticCurveTo() | 创建二次贝塞尔曲线 | | bezierCurveTo() | 创建三次贝塞尔曲线 | | arc() | 创建弧/曲线 ( 用于创建圆形或部分圆 ) | | arcTo() | 创建两切线之间的弧/曲线 | | isPointlnPath() | 如果指定的点位于当前路径中,则返回 true 否则返回 false | ## 转换 | 方法 | 描述 | | -------------- | ---------------------------------------------- | | scale() | 缩放当前绘图至更大或更小 | | rotate() | 旋转当前绘图 | | translate() | 重新映射画布上的 (0,0) 位置 | | transform() | 替换绘图的当前转换矩阵 | | setTransform() | 将当前转换重置为单位矩阵,然后运行 transform() | ## 文本 | 属性 | 描述 | | ------------ | -------------------------------------- | | font | 设置或返回文本内容的当前字体属性 | | textAlign | 设置或返回文本内容当前的对齐方式 | | textBaseline | 设置或返回在绘制文本时使用当前文本基线 | | 方法 | 描述 | | ------------- | ---------------------------- | | fillText() | 在画布上绘制 "被填充的" 文本 | | strokeText() | 在画布时绘制文本 (无填充) | | measureText() | 返回包含指定文本宽度的对象 | ## 图像绘制 | 方法 | 描述 | | ----------- | ------------------------ | | drawlmage() | 向画布上绘制图像,或视频 | ## 像素操作 | 属性 | 描述 | | ------ | --------------------------------------------------- | | width | 返回 lmageData 对象的宽度 | | heigth | 返回 lmageData 对象的高度 | | data | 返回一个对象,其包含指定的 lmageData 对象的图像数据 | | 方法 | 描述 | | ----------------- | --------------------------------------------------------- | | createlmageData() | 创建新的 空白的 lmageData 对象 | | getlmageData() | 返回 lmageData 对象,该对象为画布上指定的矩形复制像素数据 | | putlmageData() | 把图像数据 ( 从指定的 lmageData 对象)放回画布上 | ## 合成 | 属性 | 描述 | | ------------------------ | ------------------------------------ | | globalAlpha | 设置或返回绘图的当前 alpha 或透明度 | | globalCompositeOperation | 设置或返回新图像如何绘制到已有的图上 |
笔记
2021-06-07
75℃
0
0