想要學會這個漂亮的煙花嗎?快來跟著學習吧~
<div class="container"></div>
我們只需要一個盒子表示煙花爆炸范圍就可以了
fire是煙花 注意添加絕對定位
<style> .container{ margin: 0 auto; height: 500px; width: 1200px; background: black; position: relative; overflow: hidden; } .fire{ width: 10px; background: white; height: 10px; /* border-radius: 50%; */ position: absolute; bottom: 0; } </style>
需要用到一個鼠標點擊的位置,一個div選擇器,一個爆炸樣式
function Firework(x,y,selector,type){ //此處獲取對象的方式為單例的思想,避免重復獲取相同的元素 if(Firework.box && selector === Firework.box.selector){ this.box = Firework.box.ele; }else{ Firework.box = { ele:document.querySelector(selector), selector:selector } this.box = Firework.box.ele; } this.type = type; this.init(x,y) }
function animation(ele,attroptions,callback){ for(var attr in attroptions){ attroptions[attr] ={ target:attroptions[attr], inow:parseInt(getComputedStyle(ele)[attr]) } } clearInterval(ele.timer); ele.timer = setInterval(function(){ for(var attr in attroptions ){ var item = attroptions[attr] var target = item.target; var inow = item.inow; var speed = (target - inow)/10; speed = speed>0?Math.ceil(speed):Math.floor(speed); if(Math.abs(target - inow) <= Math.abs(speed)){ ele.style[attr] = target+"px"; delete attroptions[attr]; for(var num in attroptions){ return false; } clearTimeout(ele.timer); if(typeof callback === "function")callback(); }else{ attroptions[attr].inow += speed; ele.style[attr] = attroptions[attr].inow+"px"; } } },30) }
Firework.prototype = { constructor:Firework, //初始化 init:function(x,y){ //創建一個煙花 this.ele = this.createFirework(); //xy為鼠標落點 this.x = x ; this.y = y; //maxXy為最大運動范圍 this.maxX = this.box.offsetWidth - this.ele.offsetWidth; this.maxY = this.box.offsetHeight - this.ele.offsetHeight; //初始化結束后 煙花隨機顏色 this.randomColor(this.ele); //煙花升空 this.fireworkUp(this.ele); }, //創造煙花 createFirework:function(){ var ele = document.createElement("div"); ele.className = "fire"; this.box.appendChild(ele); return ele; }, //煙花升空 fireworkUp:function(ele){ ele.style.left = this.x + "px"; //此處用到剛剛封裝的運動方法 animation(ele,{top:this.y},function(){ ele.remove(); this.fireworkBlast() }.bind(this)); }, //煙花爆炸 fireworkBlast:function(){ for(var i = 0 ; i < 20; i++){ var ele = document.createElement("div"); ele.className = "fire"; ele.style.left = this.x + "px"; ele.style.top = this.y + "px"; this.box.appendChild(ele); ele.style.borderRadius = "50%"; this.randomColor(ele); //判定一下輸入的爆炸方式是原型煙花 還是散落煙花 由此更改獲取的煙花位置 animation(ele,this.type === "circle"?this.circleBlast(i,20): this.randomPosition(),function(cale){ cale.remove(); }.bind(this,ele)) } }, //圓形爆炸位置 circleBlast:function(i,total){ var r = 200; var reg = 360 / total *i; var deg = Math.PI / 180 *reg; return { left:r * Math.cos(deg) + this.x , top:r * Math.sin(deg) + this.y } }, //隨機顏色 randomPosition:function(){ return { left : Math.random()*this.maxX, top : Math.random()*this.maxY } }, randomColor:function(ele){ var color = "#" + parseInt(parseInt("ffffff",16)*Math.random()).toString(16).padStart(6,0); return ele.style.backgroundColor = color; } }
document.querySelector(".container").addEventListener("click",function(evt){ var e = evt||event; new Firework(e.offsetX,e.offsetY,".container","circle") new Firework(e.offsetX,e.offsetY,".container") })
全部代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .container{ margin: 0 auto; height: 500px; width: 1200px; background: black; position: relative; overflow: hidden; } .fire{ width: 10px; background: white; height: 10px; /* border-radius: 50%; */ position: absolute; bottom: 0; } </style> </head> <body> <div class="container"></div> <script src="./utils.js"></script> <script> function animation(ele,attroptions,callback){ for(var attr in attroptions){ attroptions[attr] ={ target:attroptions[attr], inow:parseInt(getComputedStyle(ele)[attr]) } } clearInterval(ele.timer); ele.timer = setInterval(function(){ for(var attr in attroptions ){ var item = attroptions[attr] var target = item.target; var inow = item.inow; var speed = (target - inow)/10; speed = speed>0?Math.ceil(speed):Math.floor(speed); if(Math.abs(target - inow) <= Math.abs(speed)){ ele.style[attr] = target+"px"; delete attroptions[attr]; for(var num in attroptions){ return false; } clearTimeout(ele.timer); if(typeof callback === "function")callback(); }else{ attroptions[attr].inow += speed; ele.style[attr] = attroptions[attr].inow+"px"; } } },30) } function Firework(x,y,selector,type){ if(Firework.box && selector === Firework.box.selector){ this.box = Firework.box.ele; }else{ Firework.box = { ele:document.querySelector(selector), selector:selector } this.box = Firework.box.ele; } this.type = type; this.init(x,y) } Firework.prototype = { constructor:Firework, //初始化 init:function(x,y){ this.ele = this.createFirework(); this.x = x ; this.y = y; this.maxX = this.box.offsetWidth - this.ele.offsetWidth; this.maxY = this.box.offsetHeight - this.ele.offsetHeight; this.randomColor(this.ele); this.fireworkUp(this.ele); }, //創造煙花 createFirework:function(){ var ele = document.createElement("div"); ele.className = "fire"; this.box.appendChild(ele); return ele; }, fireworkUp:function(ele){ ele.style.left = this.x + "px"; animation(ele,{top:this.y},function(){ ele.remove(); this.fireworkBlast() }.bind(this)); }, //煙花爆炸 fireworkBlast:function(){ for(var i = 0 ; i < 20; i++){ var ele = document.createElement("div"); ele.className = "fire"; ele.style.left = this.x + "px"; ele.style.top = this.y + "px"; this.box.appendChild(ele); ele.style.borderRadius = "50%"; this.randomColor(ele); animation(ele,this.type === "circle"?this.circleBlast(i,20): this.randomPosition(),function(cale){ cale.remove(); }.bind(this,ele)) } }, circleBlast:function(i,total){ var r = 200; var reg = 360 / total *i; var deg = Math.PI / 180 *reg; return { left:r * Math.cos(deg) + this.x , top:r * Math.sin(deg) + this.y } }, randomPosition:function(){ return { left : Math.random()*this.maxX, top : Math.random()*this.maxY } }, randomColor:function(ele){ var color = "#" + parseInt(parseInt("ffffff",16)*Math.random()).toString(16).padStart(6,0); return ele.style.backgroundColor = color; } } document.querySelector(".container").addEventListener("click",function(evt){ var e = evt||event; new Firework(e.offsetX,e.offsetY,".container","circle") new Firework(e.offsetX,e.offsetY,".container") }) </script> </body> </html>
———————————————— 版權聲明:本文為CSDN博主「SpongeBooob」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/qq_41383900/article/details/105026768
許多人都有這樣一種映像,NodeJS比較快; 但是因為其是單線程,所以它不穩定,有點不安全,不適合處理復雜業務; 它比較適合對并發要求比較高,而且簡單的業務場景。
在Express的作者的TJ Holowaychuk的 告別Node.js一文中列舉了以下罪狀:
Farewell NodeJS (TJ Holowaychuk)
? you may get duplicate callbacks
? you may not get a callback at all (lost in limbo)
? you may get out-of-band errors
? emitters may get multiple “error” events
? missing “error” events sends everything to hell
? often unsure what requires “error” handlers
? “error” handlers are very verbose
? callbacks suck
其實這幾條主要吐嘈了兩點: node.js錯誤處理很扯蛋,node.js的回調也很扯蛋。
事實上NodeJS里程確實有“脆弱”的一面,單線程的某處產生了“未處理的”異常確實會導致整個Node.JS的崩潰退出,來看個例子, 這里有一個node-error.js的文件:
var http = require('http'); var server = http.createServer(function (req, res) { //這里有個錯誤,params 是 undefined var ok = req.params.ok; res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World '); }); server.listen(8080, '127.0.0.1'); console.log('Server running at http://127.0.0.1:8080/');
啟動服務,并在地址欄測試一下發現 http://127.0.0.1:8080/ 不出所料,node崩潰了
$ node node-error Server running at http://127.0.0.1:8080/ c:githubscript ode-error.js:5 var ok = req.params.ok; ^ TypeError: Cannot read property 'ok' of undefined at Server.<anonymous> (c:githubscript ode-error.js:5:22) at Server.EventEmitter.emit (events.js:98:17) at HTTPParser.parser.onIncoming (http.js:2108:12) at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:121:23) at Socket.socket.ondata (http.js:1966:22) at TCP.onread (net.js:525:27)
其實Node.JS發展到今天,如果連這個問題都解決不了,那估計早就沒人用了。
我們可以uncaughtException來全局捕獲未捕獲的Error,同時你還可以將此函數的調用棧打印出來,捕獲之后可以有效防止node進程退出,如:
process.on('uncaughtException', function (err) { //打印出錯誤 console.log(err); //打印出錯誤的調用棧方便調試 console.log(err.stack); });
這相當于在node進程內部進行守護, 但這種方法很多人都是不提倡的,說明你還不能完全掌控Node.JS的異常。
我們還可以在回調前加try/catch,同樣確保線程的安全。
var http = require('http'); http.createServer(function(req, res) { try { handler(req, res); } catch(e) { console.log(' ', e, ' ', e.stack); try { res.end(e.stack); } catch(e) { } } }).listen(8080, '127.0.0.1'); console.log('Server running at http://127.0.0.1:8080/'); var handler = function (req, res) { //Error Popuped var name = req.params.name; res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello ' + name); };
這種方案的好處是,可以將錯誤和調用棧直接輸出到當前發生的網頁上。
標準的HTTP響應處理會經歷一系列的Middleware(HttpModule),最終到達Handler,如下圖所示:
這 些Middleware和Handler在NodeJS中都有一個特點,他們都是回調函數,而回調函數中是唯一會讓Node在運行時崩潰的地方。根據這個 特點,我們只需要在框架中集成一處try/catch就可以相對完美地解決異常問題,而且不會影響其它用戶的請求request。
事實上現在的NodeJS WEB框架幾乎都是這么做的,如 OurJS開源博客所基于的 WebSvr
就有這么一處異常處理代碼:
Line: 207 try { handler(req, res); } catch(err) { var errorMsg = ' ' + 'Error ' + new Date().toISOString() + ' ' + req.url + ' ' + err.stack || err.message || 'unknow error' + ' ' ; console.error(errorMsg); Settings.showError ? res.end('<pre>' + errorMsg + '</pre>') : res.end(); }
那么不在回調中產生的錯誤怎么辦?不必擔心,其實這樣的node程序根本就起不起來。
此外node自帶的 cluster 也有一定的容錯能力,它跟nginx的worker很類似,但消耗資源(內存)略大,編程也不是很方便,OurJS并沒有采用此種設計。
現 在已經基本上解決了Node.JS因異常而崩潰的問題,不過任何平臺都不是100%可靠的,還有一些錯誤是從Node底層拋出的,有些異常 try/catch和uncaughtException都無法捕獲。之前在運行ourjs的時侯,會偶爾碰到底層拋出的文件流讀取異常,這就是一個底層 libuv的BUG,node.js在0.10.21中進行了修復。
面對這種情況,我們就應該為nodejs應用添加守護進程,讓NodeJS遭遇異常崩潰以后能馬上復活。
另外,還應該把這些產生的異常記錄到日志中,并讓異常永遠不再發生。
node-forever 提供了守護的功能和LOG日志記錄功能。
安裝非常容易
[sudo] npm install forever
使用也很簡單
$ forever start simple-server.js $ forever list [0] simple-server.js [ 24597, 24596 ]
還可以看日志
forever -o out.log -e err.log my-script.js
使用node來守護的話資源開銷可能會有點大,而且也會略顯復雜,OurJS直接在開機啟動腳本來進程線程守護。
如在debian中放置的 ourjs 開機啟動文件: /etc/init.d/ourjs
這個文件非常簡單,只有啟動的選項,守護的核心功能是由一個無限循環 while true; 來實現的,為了防止過于密集的錯誤阻塞進程,每次錯誤后間隔1秒重啟服務
WEB_DIR='/var/www/ourjs' WEB_APP='svr/ourjs.js' #location of node you want to use NODE_EXE=/root/local/bin/node while true; do { $NODE_EXE $WEB_DIR/$WEB_APP config.magazine.js echo "Stopped unexpected, restarting " } 2>> $WEB_DIR/error.log sleep 1 done
錯誤日志記錄也非常簡單,直接將此進程控制臺當中的錯誤輸出到error.log文件即可: 2>> $WEB_DIR/error.log 這一行, 2 代表 Error。
這篇文章從一個初學者的角度,復習一波JSP。
一.概念
Java Server Pages: java服務器端頁面
可以理解為:一個特殊的頁面,其中既可以指定定義html標簽,又可以定義java代碼
用于簡化書寫?。。?br />
二.原理
本質是一個Servlet
三.腳本
定義:Jsp定義java代碼的方式
<% 代碼 %>:定義的java代碼,在service方法中。service方法中可以定義什么,該腳本中就可以定義什么。
<%! 代碼 %>:定義的java代碼,在jsp轉換后的java類的成員位置。
<%= 代碼 %>:定義的java代碼,會輸出到頁面上。輸出語句中可以定義什么,該腳本中就可以定義什么。
四.內置對象
對象名 實現接口或繼承類 作用
PageContext 當前頁面共享數據,還可以獲取其他八個內置對象
request HttpServletRequest 一次請求訪問的多個資源(轉發)
session HttpSession 一次會話的多個請求間
application ServletContext 所有用戶間共享數據
response HttpServletResponse 響應對象
page Object 當前頁面(Servlet)的對象 this
out JspWriter 輸出對象,數據輸出到頁面上
config ServletConfig Servlet的配置對象
expection Throwable 異常對象
五.注釋
1.html注釋
<!-- -->:只能注釋html代碼片段
2.jsp注釋
<%-- --%>:可以注釋所有
六.編譯指令
作用
用于配置JSP頁面,導入資源文件
格式
<%@ 指令名稱 屬性名1=屬性值1 屬性名2=屬性值2 ... %>
分類
1.page
配置JSP頁面的
1. contentType:等同于response.setContentType()
*設置響應體的mime類型以及字符集
* 設置當前jsp頁面的編碼(只能是高級的IDE才能生效,如果使用低級工具,則需要設置pageEncoding屬性設置當前頁面的字符集)
2.import:導包
3. errorPage:當前頁面發生異常后,會自動跳轉到指定的錯誤頁面
4.isErrorPage:標識當前也是是否是錯誤頁面。
* true:是,可以使用內置對象exception
* false:否。默認值。不可以使用內置對象exception
2.include
頁面包含的。導入頁面的資源文件
<%@include file="top.jsp"%>
3.導入資源
導入資源
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
prefix:前綴,自定義的
1
七.動作指令
作用
動作指令與編譯指令不間,編譯指令是通知 Servlet 引擎的處理消息,而動作指令只是運行時的腳本動作。編譯指令在將JSP 編譯成 Servlet 時起作用:處理指令通??商鎿Q成 Java腳本,是 JSP腳本的標準化寫法。
分類
指令 作用
jsp:forward 執行頁面轉向,將請求的處理轉發到下一個頁面。
jsp:param 用于傳遞參數,必須與其他支持參數曲標簽一起使用。
jsp:include 用于動態引入一個 JSP 頁面。
jsp:plugin 用于下載 JavaBean 或 Applet 到客戶端執行。
jsp:useBean 使用 JavaBean。
jsp:setProperty 修改 JavaBean 實例的屬性值。
jsp:getProperty 獲取 JavaBean 實例的屬性值。
具體細節:
jsp:forward:
動作把請求轉到另外的頁面??梢赞D發靜態的HTML頁面,也可以轉發動態的JSP頁面,或者轉發到容器中的servlet jsp:forward標記只有一個屬性page。 page屬性包含的是一個相對URL。 page的值既可以直接給出,也可以在請求的時候動態計算。
jsp:param
用于設定參數值,這個指令不能單獨使用 可以與以下三個指令結合使用:
jsp:include :用于將參數值出入被導入頁面
jsp:forword : 用于將參數值傳入被轉向頁面
jsp:plugin : 用于將參數值傳入頁面中javaBean的實例
jsp:include
(拿目標頁面插入原有頁面)該動作是一個動態的include指令,也用于帶入某個頁面,他不會導入被include頁面的編譯指令,僅僅導入頁面的body內容插入到本頁面
該動作把指定文件插入正在生成的頁面。其語法如下: flush:用于指定輸出緩存是否轉移到被導入的文件中, true:包含在被導入的文件中 false:包含在源文件中
前面已經介紹過include指令,它是在JSP文件被轉換成Servlet的時候引入文件,而這里的jsp:include動作不同,插入文件的時間是在頁面被請求的時候。j
sp:include動作的文件引入時間決定了它的效率要稍微差一點,而且被引用文件不能包含某些JSP代碼(例如不能設置HTTP頭),但它的靈活性卻要好得多。
jsp:plugin
用于下載服務器端的javaBean或applet到客戶端)
jsp:plugin動作用來根據瀏覽器的類型,插入通過Java插件運行Java Applet所必需的OBJECT或EMBED元素。
<jsp:plugin type="bean | applet" : 被執行的java程序的類型 code="classFileName" :被執行的文件名,必須以 .class 結尾 codebase="classFileDirectoryName" :被執行文件的所在目錄 [ name="instanceName" ] :給程序起一個名字用來標識該程序 [ archive="URIToArchive, ..." ] :指向一些要預先載入的將要使用到的類 [ align="bottom | top | middle | left | right" ] : [ height="displayPixels" ] [ width="displayPixels" ] [ hspace="leftRightPixels" ] [ vspace="topBottomPixels" ] [ jreversion="JREVersionNumber | 1.1" ] :能正確運行改程序必須的JRE的版本 [ nsplug inurl="URLToPlugin" ] [ iepluginurl="URLToPlugin" ] > [ <jsp:params> [ <jsp:param name="parameterName" value="{parameterValue | <%= expression %>}" /> ]+ </jsp:params> ] [ <jsp:fallback> text message for user </jsp:fallback> ] :當不能正確顯示該Applet時,顯示該指令中的文本提示 <jsp:plugin>
jsp:useBean
useBean:用于在jsp頁面中初始化一個java實例(如果多個jsp中需要重復使用某段代碼,可以把這段代碼定義成java類在頁面中引用)
jsp:useBean動作用來裝載一個將在JSP頁面中使用的JavaBean。這個功能非常有用,因為它使得我們既可以發揮Java組件重用的優勢,同時也避免了損失JSP區別于Servlet的方便性。
jsp:useBean動作最簡單的語法為:<jsp:useBean id=“JavaBean的名稱” class=“package.class"包名.類名” scope=“有效范圍”/>
這行代碼的含義是:“創建一個由class屬性指定的類的實例,然后把它綁定到其名字由id屬性給出的變量上”。不過,就象我們接下來會看到的,定義一個scope屬性可以讓Bean關聯到更多的頁面,它可接受四個值:request、session、page、application。此時,jsp:useBean動作只有在不存在同樣id和scope的Bean時才創建新的對象實例,同時,獲得現有Bean的引用就變得很有必要。
獲得Bean實例之后,要修改Bean的屬性既可以通過jsp:setProperty動作進行,也可以在Scriptlet中利用id屬性所命名的對象變量,通過調用該對象的方法顯式地修改其屬性。這使我們想起,當我們說“某個Bean有一個類型為X的屬性foo”時,就意味著“這個類有一個返回值類型為X的getFoo方法,還有一個setFoo方法以X類型的值為參數”。 有關jsp:setProperty動作的詳細情況在后面討論。但現在必須了解的是,我們既可以通過jsp:setProperty動作的value屬性直接提供一個值,也可以通過param屬性聲明Bean的屬性值來自指定的請求參數,還可以列出Bean屬性表明它的值應該來自請求參數中的同名變量。
在JSP表達式或Scriptlet中讀取Bean屬性通過調用相應的getXXX方法實現,或者更一般地,使用jsp:getProperty動作。
注意,包含Bean的類文件應該放到服務器正式存放Java類的目錄下,而不是保留給修改后能夠自動裝載的類的目錄。例如,對于Java Web
Server來說,Bean和所有Bean用到的類都應該放入classes目錄,或者封裝進jar文件后放入lib目錄,但不應該放到servlets下。
id:javaBean的實例名 class: javaBean的實現類 scope:指定javaBean實例的生存范圍
page:javaBean僅在該頁面有效 request:javaBean在本次請求中有效 session:
javaBean在本次session內有效 application:
javaBean在本應用內一直有效 下面是一個很簡單的例子,它的功能是裝載一個Bean,然后設置/讀取它的message屬性。
關于jsp:useBean的進一步說明 使用Bean最簡單的方法是先用下面的代碼裝載Bean: <jsp:useBean id=“name” class=“package.class” />
然后通過jsp:setProperty和jsp:getProperty修改和提取Bean的屬性。 不過有兩點必須注意。 第一,我們還可以用下面這種格式實例化Bean: <jsp:useBean …> Body </jsp:useBean>
它的意思是,只有當第一次實例化Bean時才執行Body部分,如果是利用現有的Bean實例則不執行Body部分。正如下面將要介紹的,jsp:useBean并非總是意味著創建一個新的Bean實例。
第二,除了id和class外,jsp:useBean還有其他三個屬性,即:scope、type、beanName。
id:命名引用該Bean的變量。如果能夠找到id和scope相同的Bean實例,jsp:useBean動作將使用已有的Bean實例而不是創建新的實例。
class:指定Bean的完整包名。
scope:指定Bean在哪種上下文內可用,可以取下面的四個值之一:page、request、session和application?! ∧J值是page,表示該Bean只在當前頁面內可用(保存在當前頁面的PageContext內)。
request表示該Bean在當前的客戶請求內有效(保存在ServletRequest對象內)。
session表示該Bean對當前HttpSession內的所有頁面都有效。
最后,如果取值application,則表示該Bean對所有具有相同ServletContext的頁面都有效。
scope之所以很重要,是因為jsp:useBean只有在不存在具有相同id和scope的對象時才會實例化新的對象;
如果已有id和scope都相同的對象則直接使用已有的對象,此時jsp:useBean開始標記和結束標記之間的任何內容都將被忽略。
type:指定引用該對象的變量的類型,它必須是Bean類的名字、超類名字、該類所實現的接口名字之一。請記住變量的名字是由id屬性指定的。
beanName:指定Bean的名字。如果提供了type屬性和beanName屬性,允許省略class屬性。
jsp:setProperty
jsp:setProperty用來設置已經實例化的Bean對象的屬性,有兩種用法。
首先,你可以在jsp:useBean元素的外面(后面)使用jsp:setProperty, …
第二種用法是把jsp:setProperty放入jsp:useBean元素的內部, …
jsp:setProperty動作有下面四個屬性:name:表示要設置屬性的是哪個Bean?! roperty:表示要設置哪個屬性。有一個特殊用法:如果property的值是"",表示所有名字和Bean屬性名字匹配的請求參數都將被傳遞給相應的屬性set方法?! alue:value屬性是可選的。該屬性用來指定Bean屬性的值。字符串數據會在目標類中通過標準的valueOf方法自動轉換成數字、boolean、Boolean、byte、Byte、char、Character。例如,boolean和Boolean類型的屬性值(比如“true”)通過Boolean.valueOf轉換,int和Integer類型的屬性值(比如"42")通過Integer.valueOf轉換?! alue和param不能同時使用,但可以使用其中任意一個?! aram:param是可選的。它指定用哪個請求參數作為Bean屬性的值。如果當前請求沒有參數,則什么事情也不做,系統不會把null傳遞給Bean屬性的set方法。因此,你可以讓Bean自己提供默認屬性值,只有當請求參數明確指定了新值時才修改默認屬性值。 例如,下面的代碼片斷表示:如果存在numItems請求參數的話,把numberOfItems屬性的值設置為請求參數numItems的值;否則什么也不做?! ∪绻瑫r省略value和param,其效果相當于提供一個param且其值等于property的值。進一步利用這種借助請求參數和屬性名字相同進行自動賦值的思想,你還可以在property(Bean屬性的名字)中指定“”,然后省略value和param。此時,服務器會查看所有的Bean屬性和請求參數,如果兩者名字相同則自動賦值?! ∠旅媸且粋€利用JavaBean計算素數的例子。如果請求中有一個numDigits參數,則該值被傳遞給Bean的numDigits屬性;numPrimes也類似?! spPrimes.jsp
jsp:getProperty
jsp:getProperty動作提取指定Bean屬性的值,轉換成字符串,然后輸出。
jsp:getProperty有兩個必需的屬性,即:name,表示Bean的名字;property,表示要提取哪個屬性的值。
END?。?!有什么意見可以提出來!
長路漫漫,JAVA為伴!?。?br />
————————————————
版權聲明:本文為CSDN博主「福爾摩東」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_43688587/article/details/105017469
label默認為內聯元素,元素前后沒有換行符,并且不可以設置寬度。
如果要為label設置寬度,則需要改變label的display屬性,使其變為一個塊級元素。
方法如下:
1.增加inline-block屬性值,將label標簽變為行內塊元素(css2.1新增)
{
display
:inline-
block
;}
label{
width
:
100px
;
display
:inline-
block
;}
3.添加好后頁面上所有的label標簽會變為100pxv
JavaScript中的混淆器
隨著 AJAX 和富界面技術的發展,Javascript 在 Web 應用上的重要性越來越高,Javascript 代碼的復雜性、功能和技術含量也越來越高,對Javascript 代碼保護的需要也越來越迫切。
壓縮 compress: 去掉空格,換行,注釋等,格式緊湊,節約存儲空間。
混淆 obfuscate/garble:替換變量名或方法名,讓js不容易看懂。也做到了壓縮的效果。
加密 encrypt:一般用eval方法加密,效果與混淆相似。也做到了壓縮的效果。
我們可以通過工具進行混淆,通過工具也是目前最好的方式。推薦一個很好的混淆工具: JSObfuscator By Unest
————————————————
版權聲明:本文為CSDN博主「劉亦楓」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/liuyifeng0000/article/details/105004732
在一個asp.net 的項目中,前端通過ajax將富文本中的文字內容post到服務端的一個ashx中,在ashx中嘗試讀取參數值時,
結果報錯:“從客戶端中檢測到有潛在危險的 Request.Form 值”
#事故分析
由于在asp.net中,Request提交時出現有html代碼字符串時,程序系統會認為其具有潛在危險的值。會報出“從客戶端 中檢測到有潛在危險的Request.Form值”這樣的Error。
而富文本中的內容是包含html代碼的,所以...
#解決方案:
1、前端對富文本字符串進行encodeURI編碼,服務端進行HttpUtility.UrlDecode解碼操作;
前端代碼:
var str = '<p><span style="color: #00B0F0;"><em><strong>我想留在你的身邊,</strong></em></span><br/></p><p><span style="color: #7030A0;"><strong><span style="text-decoration: underline;">深情款款多么可憐;</span></strong></span></p>';
$(function() {
$.ajax({
type: "post",
url: "TestHandle.ashx",
data: { Title: 'jack', Content: encodeURI(str) },
success: function (data) {
$("#div").html(data);
}
});
});
后端代碼:
public void ProcessRequest(HttpContext context)
{
string str = context.Request["content"];
string content = HttpUtility.UrlDecode(str);
context.Response.ContentType = "text/plain";
context.Response.Write(content);
}
效果圖:
2、前端不以form的方式提交,直接以json方式提交,服務端從request的body中讀取數據,然后反序列化,得到信息;
前端代碼:
var str = '<p><span style="color: #00B0F0;"><em><strong>我想留在你的身邊,</strong></em></span><br/></p><p><span style="color: #7030A0;"><strong><span style="text-decoration: underline;">深情款款多么可憐;</span></strong></span></p>';
var temp = { Title: 'jack', Content: str };
$.ajax({
type: "post",
url: "TestHandle.ashx",
contentType:"application/json;charset=utf-8",
data: JSON.stringify(temp),
success: function (data) {
$("#div").html(data);
}
});
后端代碼:
string bodyText;
using (var bodyReader = new System.IO.StreamReader(context.Request.InputStream))
{
bodyText = bodyReader.ReadToEnd();
}
dynamic bodyObj = JsonConvert.DeserializeObject(bodyText);
context.Response.ContentType = "text/plain";
context.Response.Write(bodyObj.Content);
效果圖:
#其他場景的解決方案:
1、aspx頁面,當前頁面進行form提交
打開當前.aspx頁面,頁頭加上代碼:validateRequest=”false”,如:
<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="false" CodeFile="default.aspx.cs" Inherits="default" %>
該方法不推薦,還有一種修改web.config配置文件的方法,強烈不推薦,就不寫在這里了;
2、在ASP.NET MVC中的解決方案
1)、針對某個實體類的單個字段設置 [AllowHtml] ,這樣提交的時候,系統就會放過該字段。
2)、前端代碼:
var str = '<p><span style="color: #00B0F0;"><em><strong>我想留在你的身邊,</strong></em></span><br/></p><p><span style="color: #7030A0;"><strong><span style="text-decoration: underline;">深情款款多么可憐;</span></strong></span></p>';
$(function () {
$.ajax({
type: "post",
url: "Home/Test",
data: { Title: 'jack', Content: str },
success: function (data) {
$("#div").html(data.ok);
}
});
});
3)、后端代碼:
public class NewInfo
{
public string Title { get; set; }
[AllowHtml]
public string Content { get; set; }
}
#寫在最后
該文只是淺顯的總結一下,其中涉及的xss方面,沒有詳細考慮,歡迎指正!
前言
開發中,經常會用到js的Array數組的各種迭代函數map(),filter(),some(),every(),forEach(),find() findIndex(),也是在ES6中新增一些遍歷函數。同樣是不是也是一道面試題,說說ES6新增的一些新特性????
?開始正文some()函數
?一、對some()函數的定義:
some():用于檢測數組中的元素是否滿足指定條件(函數提供);
some()方法會依次執行數組中的每一個元素:
如果有一個元素滿足條件,則表達式返回true,剩余的元素不會再執行檢測。
如果沒有滿足條件的元素,則返回false。
注意:
some()不會對空數組進行檢測。
some() 不會改變原始數組。
?二、瀏覽器支持
表格中的數字表示支持該方法的第一個瀏覽器的版本號。
?三、語法
array.some(function(currentValue,index,arr),thisValue)
1
參數說明:
?三、示例
<script>
var ages = [4, 12, 16, 20];
function checkAdult(age) {
return age >= document.getElementById("ageToCheck").value;
}
function myFunction() {
document.getElementById("demo").innerHTML = ages.some(checkAdult);
}
</script>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>隔行變色</title>
</head>
<body>
<table id="mytable" align="center" width="80%" border="1">
<tr bgcolor="#cccccc">
<td>aaa</td>
<td>aaa</td>
<td>aaa</td>
</tr>
<tr>
<td>bbb</td>
<td>bbb</td>
<td>bbb</td>
</tr>
<tr>
<td>ccc</td>
<td>ccc</td>
<td>ccc</td>
</tr>
</table>
<script type="text/javascript">
window.onload=function(){
//獲取mytable中標簽名為tr的字節點
mytable=document.getElementById("mytable");
trs=mytable.getElementsByTagName("tr");
len=trs.length;
flag=true;
for(i=0;i<len;i++){
if(flag){
//每隔一行設置背景色
var tr=document.getElementsByTagName("tr")[i].setAttribute("bgcolor","#cccccc");
flag=false;
}else{
flag=true;
}
}
}
</script>
</body>
</html>
/Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
<script type="text/javascript"> var Sys = {}; var ua = navigator.userAgent.toLowerCase(); var s; (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] : (s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] : (s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] : (s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] : (s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0; //以下進行測試 if (Sys.ie) document.write('IE: ' + Sys.ie); if (Sys.firefox) document.write('Firefox: ' + Sys.firefox); if (Sys.chrome) document.write('Chrome: ' + Sys.chrome); if (Sys.opera) document.write('Opera: ' + Sys.opera); if (Sys.safari) document.write('Safari: ' + Sys.safari); </script>
PC端只有Chrome有Safari字段嗎?為什么不需要判斷其他瀏覽器?
其實360,QQ等瀏覽器的userAgent字段也會帶有Safari字段,但是由于他們基于Chrome二次開發的,所有也會攜帶有Chrome字段。
所以「匹配規則:擁有Safari字段,并且沒有Chrome字段」就可以了。
接下來是修改元素樣式
<html> <head> <style> #a{ width:700px; height:300px; font-size:50px; color:red; background-color:grey; z-index:2; position:absolute; top:1300px; left:200px; display:none; } </style> </head> <body> <div id="a"></div> </body> <script type="text/javascript"> //假設想修改display為block function modify(){ //1.原生Js法 var a= document.getElementById("a"); a.style.display="block"; //2.用JQuery的css方法 var a =$("#a"); a.css("display","block"); //3.用JQuery的attr方法 var a =$("#a"); a.attr("style","display:block"); } </script> </html>
這樣就可以根據不同瀏覽器寫出不同的樣式適配啦
JS中數據類型轉換
目前為止,我了解到的JavaScript中共有6種類型。通過typeof關鍵字可以查看類型名稱。
數據的類型:
字符串:若值為字符串,則顯示為String。字符串使用單引號或雙引號括起來。在控制臺顯示為黑色。
數字:若值為數字,則顯示為Number。在控制臺顯示為藍色。
布爾值:若值為布爾值,則顯示為Boolean。它的值只有”true”和”false”。
對象:若值為對象,則顯示為Object。
未定義:若值未定義,也就是僅僅聲明,但未進行賦值,則顯示為Undefined。
空值:若值為指向不引用對象的指針,則顯示為Null,它與Undefined不同,以后慢慢深入了解。
以下表格詳細寫出了各種情況下相互轉換的結果,可作為輔助記憶。
值 轉換為字符串 轉換為數字 轉換為布爾值 轉換為對象
undefined “undefined” NaN false throw TypeError
null “null” 0 false throw TypeError
true “true” 1 new Boolean(“true”)
false “false” 0 new Boolean(“false”)
“” 0 false new String("")
“1.2” 1.2 true new String(“1.2”)
“1.2a” NaN true new String(“1.2a”)
“aaa” NaN true new String(“aaa”)
0 “0” false new Number(0)
1 “1” true new Number(1)
NaN “NaN” false new Number(NaN)
Infinity “Infinity” true new Number(Infinity)
[] “” 0 true
[9] “9” 9 true
[“a”“b”] “a,b” NaN true
在Js中,數據類型可以相互轉換,轉換的方式有兩種,隱式轉換和強制轉換,首先來說一些隱式轉換。在進行代碼書寫時,要經常提醒自己所使用的元素是什么數據類型,在進行某些操作后是否會導致數據類型的變化,原因就是Js會對數據進行類型的隱式轉換。
隱式轉換舉例:
(+)加法運算的隱式轉換:加號兩邊只要出先了字符串,就自動將兩者均轉化為字符串,使兩個字符串發生“拼接”,最后生成的結果也是一個字符串;如果前后都不是字符串,則轉化為數字類型進行計算。
(-、*、/、%)其他算數運算的隱式轉換:前后都轉化為數字類型進行計算。
(?。┻壿嫹堑碾[式轉換:他會將他后面的變量或表達式轉換為布爾值。
(<,>)比較運算符的轉換:如果前后存在一個數字,會對另一個轉化為數字進行比較;如果前后均為字符串,會依次比較對應字符的編碼大小,老大比老大,老二比老二,依次進行。
(&&,||)邏輯運算符的轉換:先將前后都轉化為布爾值再進行判斷,要記住的是,只有undefined,null,0,””,NaN會轉化成為false,其他都是true。
(== 、===)這里作為補充說明,null與Undefined相等但不全等,NaN與任何都不相等。
強制轉換的方式:
1.轉化為字符串
String(里面寫待轉化的內容):沒什么好解釋的,就是強制將你所看到的轉化為你所看到的。
toString(里面寫目標數字是幾進制),寫法為:待轉化內容.toString(目標內容是幾進制)。括號內不寫時默認為10。
toFixed(保留小數的位數),寫法為待轉化內容.toFixed(保留小數的位數),存在精度誤差。
2.轉化為數字
Number(),只有所轉化內容在肉眼看到的全是數字,才會正常轉化;false會轉化為0,true會轉化為1;null會轉化為0;undefined會轉化為NaN;其他情況均為NaN。
parseInt(待轉化內容,待轉化內容的進制方式),與toString互為逆運算,不寫的話默認為10。如果待轉化內容為字符串,若以數字開頭,可以從開始轉換到字符前為止變成數值。布爾值,undefined,null經過轉化均為NaN。
ParseFloat(),與上面一致,不贅述。
3.轉化為布爾值
書寫方式為Boolean(),如果上面的隱式轉換你有好好看,這里很得不需要再寫了。
密碼強度驗證
需求
首先我們需要知道需求是什么? 這很重要!
要知道 我們寫的一切邏輯都是建立在需求之上
當輸入框聚焦時提示密碼要求
當密碼符合要求時 隱藏提示 并給予反饋
密碼等級低時 提示密碼等級為低
密碼等級一般時 提示密碼等級為中
密碼等級高時 提示密碼等級為高
當密碼不符合要求時 重新打開提示
思考如何構建函數
通過上面的需求 你能想到的函數時什么?你能想到的邏輯又是什么?
首先 提示的顯示隱藏我們可以用事件綁定或者事件監聽來做
其次 我們需要利用正則來判斷密碼等級
當密碼等級為低時 顯示紅色
當密碼等級為中時 顯示黃色
當密碼等級為高時 顯示綠色
最后 根據密碼等級來渲染頁面 也就是反饋給用戶的樣式
建議 :
在這里 盡量把每個函數的功能區分好 構思好
不僅要讓自己能看懂 還要讓別人能看懂
這樣的代碼才是好的代碼 可讀性更好 可維護性更高
在提示盒子的內部寫3個div 不同等級給予不同顏色不同數量的提示
密碼 : <input type="text" id="ipt"> <p id="p">請輸入6-20位的帶有數字字母或者特殊符號的密碼</p> <div class="box"> <span></span> <div></div> <div></div> <div></div> </div>
不管樣式行為再怎么花里胡哨 也一定要先把結構里要出現的元素寫出來
由于考慮到等級分為三種 所以給提示盒子分3中不同的class類名
每一個類名對應的子元素的樣式也不同
到js部分我們只需要操作class類名
就可以了
<style> *{ margin : 0 ; padding : 0 ; } //提示盒子 .box{ position : absolute; top : 2px; left : 200px; } .box div, .box span{ margin-right : 5px; width : 20px; height : 20px; float : left; } //低等級 .box.low :nth-child(2){ background : red; } //中等級 .box.middle div{ background : yellow; } .box.middle :last-child{ background: #fff; } //高等級 .box.high div{ background : green; } //提示文字默認隱藏 p{ display : none; } </style>
<script> //獲取需要操作的元素 let ipt = document.getElementById('ipt'); let p = document.getElementById('p'); let div = document.getElementsByClassName('box')[0]; var tip = false; //聚焦顯示提示的開關 //添加聚焦事件 ipt.addEventListener('focus' , () => { //由于存在用戶輸入正確的密碼失焦再操作的可能 所以需要驗證開關 if(!tip) { p.style.display = 'block'; } //默認選中文字 提升用戶體驗 ipt.select(); }) //添加輸入時的事件 ipt.addEventListener('input' , () => { //拿到用戶輸入的密碼字符串 let str = ipt.value; //當密碼不符合要求時 要及時給予反饋 及時清除樣式 if(str.length < 6 ||str.length > 20 || /[^(\da-zA-Z\_\#\@\$\^\%\*\&\!\~\+\-)]/.test(str) || str === "") { p.style.display = 'block'; removeClass(div); div.children[0].innerHTML = ""; tip = true; //如果不符合要求 就沒必要判斷等級了 直接結束判斷 return false; }else{ p.style.display = 'none'; } //判斷密碼等級 let res = level(str); //根據等級添加樣式 randerLevel(res); }) //判斷密碼等級函數 function level (str) { let level = 0; //當用戶輸入的字符串符合一定規則 讓等級+1 if(/\d+/.test(str)) { level ++; } if(/[a-zA-Z]+/.test(str)) { level ++; } if(/[\_\#\@\$\^\%\*\&\!\~\+\-]+/.test(str)) { level ++; } return level; } //添加樣式函數 function randerLevel (level) { //在添加樣式前先清空樣式 removeClass(div); div.children[0].innerHTML = ""; //根據等級添加對應的類名 switch (level) { case 1 : div.children[0].innerHTML = '低'; //元素存在不止一個類名 用 += 更好 div.className += ' low'; break; case 2 : div.children[0].innerHTML = '中'; div.className += ' middle'; break; case 3 : div.children[0].innerHTML = '高'; div.className += ' high'; break; } } //去等級類名函數 function removeClass(ele){ let reg = /low|middle|high/g; if(reg.test(ele.className)) { //不要忘記把值賦回去 replace返回的是新字符串 ele.className = ele.className.replace(reg , ""); } } </script>
當密碼等級為低時 給予紅色反饋
————————————————
版權聲明:本文為CSDN博主「豆漿不好喝」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_45178648/article/details/104885417
藍藍設計的小編 http://www.syprn.cn