javascript 代码如果访问了页面中的元素需要将 script 代码放至最后,因为此时为页面还没有完全加载,获取元素有可能会失败
css 引入格式如下:
<link rel="stylesheet" type="text/css" href="">向元素中添加事件时(如 button 中的点击时间),函数名不能与 window 中的自带函数重复,不然会导致函数不执行或其他错误,如:
<input type="button" value="清空" onclick="clear()">此时点击按钮后函数不会执行,因为 clear 与 window 中的 clear 重名
1px: 边框大小 solid: 直线
将其 style 样式中的 resize 设置为 none 即可
该属性只在其在表单中,且点击提交表单按钮时生效
向其中加入 required属性
该属性只在其在表单中,且点击提交表单按钮时生效
传统提交方法
<form action="" method=""></form> 属性值描述acceptMIME_typeHTML 5 中不支持accept-charsetcharset_list规定服务器可处理的表单数据字符集actionURL规定当提交表单时向何处发送表单数据autocompleteonoff规定是否启用表单的自动完成功能enctype见说明规定在发送表单数据之前如何对其进行编码methodgetpost规定用于发送 form-data 的 HTTP 方法nameform_name规定表单的名称novalidatenovalidate如果使用该属性,则提交表单时不进行验证target_blank_self_parent_topframename规定在何处打开 action URL使用 Ajax
$("form").submit(function() { $.ajax({ method: 'post', url: '', data: {}, success: function() {}, error: function(err) {}, ... }); });form 表单在提交时会有一个原生事件,即自动刷新页面,此时如果你采用 ajax 方法想要在提交表单后进行其他处理,由于此时事件是异步的,有一定几率会先刷新页面,随后再执行你的函数
实例如下:
... <script> function sendmessage() { $.ajax({ method: 'post', url: '/SendMessage', data: {...}, success: function() { alert("提交成功"); window.location = "/"; }, error: function(err) { alert("提交失败,请刷新重试"); console.log(err); } }); } $("form").submit(function() { sendmessage(); }); </script> ...此时 success 中的函数有一定几率被跳过
解决方法
使用 e.preventDefault() 函数阻止原生事件的发生
修改如下:
$("form").submit(function(e) { sendmessage(); e.preventDefault(); });placeholder
提示内容
type
类型
autocomplete
是否记忆化
required
作为表单的必填项
maxlength
最大字符长度
minlength
最小字符长度
将两个元素绑定起来,经常与 checkbox 连用,增强用户体验,如:
<input type="checkbox" id="remember_me"> <label for="remember_me">下次自动登录</label>去除缩进
ul { margin: 0; padding: 0; }去除标签前的标识符
li { list-style: none; margin: 10px 0; }margin 属性接受 1~4 个值。每个值可以是 <length>,<percentage>,或 auto。取值为负时元素会比原来更接近临近元素
当只指定一个值时,该值会统一应用到全部四个边的外边距上指定两个值时,第一个值会应用于上边和下边的外边距,第二个值应用于左边和右边指定三个值时,第一个值应用于上边,第二个值应用于右边和左边,第三个则应用于下边的外边距指定四个值时,依次(顺时针方向)作为上边,右边,下边,和左边的外边距length
以固定值为外边距
percentage
相对于包含块的宽度,以百分比值为外边距
auto
让浏览器自己选择一个合适的外边距。有时,在一些特殊情况下,该值可以使元素居中
用于设置元素标签在垂直方向上的位置,一般将其设置为 middle
特别的,display: flex 表示弹性布局,是一种新特性,可以让父级元素内的元素禁止换行
将其设置成和元素高度一致可使得文字垂直居中,如
div { height: 36px; line-height: 36px; }设置 outline: none; 可以去除一些元素在被选中时的边框
设置鼠标指向该元素时的形状,如 cursor: pointer; 设置为指针状
有时如果对元素指定宽度和高度会出现溢出问题(即使宽度或高度未超过父元素),此时我们可以设置 css 自动计算宽度和高度
... <li> <input style="width: 60%;"> <input style="width: calc(100% - 60%); height: auto;"> </li> ...Ajax 全称 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
Ajax 不是新的编程语言,而是一种使用现有标准的新方法
Ajax 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容
Ajax 不需要任何浏览器插件,但需要用户允许 JavaScript 在浏览器上执行
一般语法:
$.ajax({ method: 'post', url: '', data: {}, success: function() {}, error: function(err) {}, ... });jQuery 语法是通过选取 HTML 元素,并对选取的元素执行某些操作
基础语法:$(selector).action()
美元符号定义 jQuery选择符(selector)“查询"和"查找” HTML 元素jQuery 的 action() 执行对元素的操作实例:
$(this).hide() - 隐藏当前元素$(“p”).hide() - 隐藏所有 <p> 元素$(“p.test”).hide() - 隐藏所有 class=“test” 的 <p> 元素$("#test").hide() - 隐藏 id=“test” 的元素利用 jQuery 第三方插件 highlight 实现关键词高亮
<script src="https://johannburkard.de/resources/Johann/jquery.highlight-5.js"></script> <script> function search() { var value = $.trim($('#search_text').val()); var children = $('#comments_container').children(); children.each(function() { $(this).hide(); $(this).removeHighlight(value); if($(this).text().indexOf(value) >= 0) { $(this).highlight(value); $(this).show(); } }); } </script>众所周知,Web 中后端和前端可以通过 get/post 来实现信息传递,而 node.js 为我们提供的正是一种路由机制,这种机制使我们不用新建文件便可以在后端获取前端穿过来的数据,比如:
app.get(url, function(req, res) { ... });其中 url 相当于是路由器上的端口,是数据传输的桥梁,告诉 app 数据从哪来,应该到哪去
为了不使得 app.js 中的代码冗余繁杂,我们可以建立一个新的 js 文件,来专门存放路由相关的代码,并借用 moudle.exports 来实现文件间的调用
//路由文件 router.js var express = require("express"); var Message = require("./message"); var router = express.Router(); router.post('url', function(req, res) { ... }); module.exports = router; //app.js var path = require('path'); var express = require("express"); var router = require("./router"); var app = express(); app.use(router); //使用路由中的端口 app.use(express.static(path.join(__dirname, "public"))); app.listen(3000, function() { console.log('Start in port 3000...'); }); module.exports = app;先举一个栗子:
var fs = require("fs"); function get() { var Data = ""; fs.readfile(path, function(err, data) { Data = data; }); return data; }由于 node.js 中的代码是异步处理的,所以 fs.readfile(...) 函数会优先被忽略而直接执行 return 语句,最终我们会获得空字符串而无法获得文件中的数据
解决方法:使用回调函数
var fs = require("fs"); function get(callback) { fs.readfile(path, function(err, data) { if(err) { callback(err); return; } callback(err, data); }); } get(function(err, data) { if(err) { console.log(err); return; } ... //对 data 进行处理 });在 node.js 中,只能通过上述回调函数 (callback) 的方法才能获取异步函数的数据
暂时没有用到,所以理解不是很深刻,其基础形式如下:
app.use(function(req, res, next) { ... });其中 next 函数是如果满足一定要求,则接着调用下一个符合要求的中间件,路由机制就是 express 中的一种中间件
目前知道的一个应用就是如果访问不存在的地址则可以通过这种机制来实现 404 跳转,因为中间件是顺序匹配的,所以如果和所有路由中的 url 均不匹配,则会进入最后一个中间件,所以我们将如下代码放至所有路由的最后即可实现 404 跳转
app.use(function (req, res, next) { res.render('404.html'); });首先,在需要调用的 js 文件中使用 require
var func = require("func.js");方法一: 在 func.js 中使用 moudle.exports
function createTime() { ... } module.exports = { createTime: function() { return createTime(); } ... };或者
module.exports = createTime;方法二: 在 func.js 中使用 exports
exports.createTime = function() { ... }安装命令 npm install --global nodemon
一种 node 自动重启插件,可以监听 app.js 中的改动,每当按下保存后会自动重启 app.js
一种框架,用于加载公用、静态资源,可处理 get/post 请求
var path = require('path'); var express = require("express"); var app = express(); app.use(express.static(path.join(__dirname, "public"))); app.get('/GetMessage', function(req, res) { ... }); app.post('/PostMessage', function(req, res) { ... }); app.listen(3000, function() { console.log('Start in port 3000...'); });用于读写文件
//read file fs.readFile("message.json", 'utf8', function(err, data) { if(err) { console.log(err); res.status(404).send(err); } res.send(JSON.parse(data)); }); //write file fs.writeFile("message.json", JSON.stringify(data), function(err) { if(err) { console.log(err); res.status(404).send(err); } res.send(); });用于解析 post 请求中的参数
app.post('/PostMessage', function(req, res) { var comment = ""; req.on('data', function(data) { comment += data; }); res.on('end', function(req, res) { //parse用于将其解析为对象 var comment1 = querystring.parse用于将其解析为对象(comment); //stringify用于将其解析为字符串 var comment2 = querystring.stringify(comment); res.send(); }); });注意由于 js 的函数是异步处理的,所以所有处理的函数一定要放到 res.on(…) 的 function 里面,另外假设要先读取文件后写入文件,也要将写入的函数放在读取的 function 里面,如:
app.post('/SendMessage', function(req, res) { var comment = ""; req.on('data', function(data) { comment += data; }); req.on('end', function() { fs.readFile("message.json", 'utf8', function(err, data) { if(err) { console.log(err); fs.writeFile("message.json", JSON.stringify([]), function(err) { if(err) { console.log(err); res.status(404).send(err); } res.send(); }); res.status(404).send(err); } fs.writeFile("message.json", "", function(err) { if(err) { console.log(err); res.status(404).send(err); } res.send(); }); }); }); });自动收发邮件的第三方包,其用法如下:
var nodemalier = require("nodemailer"); var mailTransport = nodemalier.createTransport({ service: "qq", secureConnection: true, auth : { user : '发送者邮箱', pass : 'SMTP授权码' } }); router.get('/SendEmail', function(req, res) { Email_code = Message.CreateEmailCode(); var options = { from: "发送者 <发送者邮箱>", to: '接收者邮箱', subject: "邮件标题", html: "邮件内容,支持html语法" }; mailTransport.sendMail(options, (err, info) => { ... }); });node.js 连接本地 mysql 数据库的第三方包,其用法如下:
var mysql = require("mysql"); var connection = mysql.createConnection({ host: "localhost", user: "root", password: "root", database: "database", port: 3306, dateStrings: true }); //查询 exports.login = function(info, callback) { var sql = "select * from user where (username = '" + info.username + "' or email = '" + info.username + "') and password = '" + info.password + "';"; connection.query(sql, function(err, result) { if(err) { console.log(err); callback(err); } callback(null, result[0].username); }); }; //插入 exports.register = function(data, callback) { var sql = "insert user(username, password, email, createtime) values(?, ?, ?, ?);"; connection.query(sql, [data.username, data.password, data.email, data.createtime], function(err) { if(err) { callback(err); return; } callback(null); }); }; //删除 exports.deletemessage = function(username, id, callback) { var sql = "delete from message where username = ? and id = ?;"; connection.query(sql, [username, id], function(err, result) { if(err) { callback(err); return; } callback(null, result.affectedRows); }); } //修改 exports.changepassword = function(username, new_password, callback) { var sql = "update user set password = ? where (username = ? or email = ?);"; connection.query(sql, [new_password, username, username], function(err, result) { if(err) { callback(err); return; } callback(null, result.affectedRows); }); }用于将用户的数据保存到服务端,如记住密码等
//一定要将其放在使用路由之前 app.use(session({ secret: 'CUG_YZL', //加密字符串 cookie: { httpOnly: true, //是否禁止在前端通过 JS 代码进行修改 maxAge: 1000 * 60 * 60 * 24 //session 保存的最大时间 }, rolling: true, //当用户在页面有操作时自动更新 session 失效时间 resave: true, //允许重复保存 //是否强制将未初始化的 session 存储(不知道什么意思,只知道 rolling 为 true 时候其必须为 false) saveUninitialized: false }));如果想要在重新提交请求是修改其有效时间,可以采用以下这种办法:
router.post('/Login', function(req, res) { var data = ""; req.on('data', function(chunk) { data += chunk; }); req.on('end', function() { ... var hour = 1000 * 60 * 60 * 24 * 30; req.session.cookie.expires = new Date(Date.now() + hour); //修改其到期时间 req.session.cookie.maxAge = 100 * hour; //修改其有效时间 ... }); });一种加密算法,一般用于对用户密码进行加密操作
var crypto = require("crypto"); const hash_key = "AVs5pq"; router.post('/Login', function(req, res) { var data = ""; req.on('data', function(chunk) { data += chunk; }); req.on('end', function() { data = querystring.parse(data); //注意每次加密时都要重新定义一个 md5 var md5 = crypto.createHash("md5", hash_key); data.password = md5.update(data.password).digest("hex"); ... }); });一种渲染框架
<body> <div id="comment"> <div id="head"> <h1>留言板</h1> <button onclick="javascript:window.location.href='./html/comment.html'">写留言</a></button> </div> <div id="comments_container"> <ul> {{ each comments }} <li class="newslist"> {{ $value.name }}说: {{ $value.message }} <span>{{ $value.datatime }}</span> </li> {{ /each }} </ul> </div> </div> </body> <script> window.onload = function() { $.ajax({ method: "get", url: "/GetMessage", data: {}, success: function(data) { var ret = template('comment', { comments: data }); document.getElementById('comment').innerHTML = ret; }, error: function(err) { console.log(err); } }); }; </script>要禁止字符串转义可以使用 {{@value}},注意千万不要加空格,否则会报错
在一个项目中,使用 art-template 对 table 内的单元格进行渲染,报错如下:
template-web.js:2 Uncaught TemplateError: comment:21:33 19| </thead> 20| <tbody><tr> >> 21| <td>{{ $value.name }}</td> 22| <td>{{ $value.message }}</td> 23| <td>{{ $value.datatime }}</td> 24| </tr></tbody> RuntimeError: Cannot read property 'name' of undefined核心代码如下:
... <table style="margin-top: 10px;"> <thead> <tr> <td><b>发言者</b></td> <td><b>内容</b></td> <td><b>发布时间</b></td> </tr> </thead> <tbody> {{ each comments }} <tr> <td>{{ $value.name }}</td> <td>{{ $value.message }}</td> <td>{{ $value.datatime }}</td> </tr> {{ /each }} </tbody> </table> ...将 table 模块的代码使用 <script type="text/html" id="..."></script> 包裹,在 js 代码中动态改变相关因素的 innerHTML
具体实例如下:
... <div id="comments_container"> <script type="text/html" style="display: none;" id="Table"></script> <table style="margin-top: 10px;"> <thead> <tr> <td><b>发言者</b></td> <td><b>内容</b></td> <td><b>发布时间</b></td> </tr> </thead> <tbody> {{ each comments }} <tr> <td>{{ $value.name }}</td> <td>{{ $value.message }}</td> <td>{{ $value.datatime }}</td> </tr> {{ /each }} </tbody> </table> </script> </div> ... <script> window.onload = function() { $.ajax({ method: "get", url: "/GetMessage", data: {}, success: function(data) { var ret = template('comment', { comments: data }); document.getElementById('comment').innerHTML = ret; document.getElementById("comments_container").innerHTML = document.getElementById("Table").innerHTML; }, error: function(err) { console.log(err); } }); }; </script>将 art-template 与 express 结合的渲染工具,可以在后端通过 res.render(url, data) 方法对页面进行跳转并渲染,并且支持设置模板页面,大大缩减代码量
可以将某些页面的公共部分整合出来,并通过渲染语法动态加载页面,大大缩减了代码量,如:
<!-- 模板页面 layout.html --> <!DOCTYPE html> <html lang="zh-cmn-Hans"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" type="text/css" href="./public/css/style.css"> <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script src="./public/js/main.js"></script> {{ block 'head' }} {{ /block }} </head> <body> {{ block 'header' }} {{ /block }} {{ block 'content' }} {{ /block }} {{ include '../_partitals/footer.html' }} </body> {{ block 'script' }} {{ /block }} </html> <!-- 底部 footer.html --> <div id="copyright"> ... </div> <!-- 首页 index.html --> {{ extend './_layout/layout.html' }} {{ block 'head' }} <title>留言板</title> {{ /block }} {{ block 'header' }} <div id="head"> <h1>留言板</h1> <button onclick="javascript:window.location.href='comment'">写留言</a></button> </div> {{ /block }} {{ block 'content' }} <div id="comments_container"> <hr/> {{ each comments }} <div style="text-align: left; margin-left: 10px;"> <b>@{{ $value.name }}</b> <span style="font-size: 14px;">{{ $value.datatime }}</span> <p> {{ $value.message }}</p> </div> <hr/> {{ /each }} </div> {{ /block }}其中 {{ include … }} 用于加载其他页面,{{ block … }} 为自定义模块,{{ extend … }} 用于继承模板页面
故名思议,同步即为顺序执行,而异步则是指操作系统的调度机制使得代码不按顺序执行,如上文提到的文件读写问题等等
问了解决这个问题,我们引入了 promise 工具
promise 可以将异步操作队列化,使其按照用户希望的顺序执行,并返回预期的结果
promise 有三种状态:
pending
待定状态,操作处于队列中,等待处理
fulfilled
成功状态,操作已被成功执行
rejected
执行失败
promise 仅可能处于一种状态,并且当其状态改变时会立刻触发 then 函数中的后续操作
简单实例如下:
var p = new Promise(function(resolve, reject) { ... if(success) { resolve(data); } else { reject(err); } }); p.then(function(data) { console.log(data); }, function(err) { console.log(err); });promise 一旦被创建(new),就会立即执行内部的定义函数,并返回结果执行 then 中的后续操作
将相对路径改为绝对路径
var path = require("path"); var datapath = path.join(__dirname, "/message.json");如果要判断 bool 类型,应当使用 Bool == 'true' 来判断
zh-CN 已经被废弃了,应该使用 zh-cmn-Hans
<html lang="zh-cmn-Hans">