Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
幾天我在面試前端開發(fā)同學(xué)的時候,有問到關(guān)于margin基礎(chǔ)布局相關(guān)內(nèi)容的過程中,發(fā)現(xiàn)很多同學(xué)基本解釋不清楚,今天剛好有點時間就整理了一篇筆記出來。就以下5點在CSS布局經(jīng)常會用到的經(jīng)典布局解決方案。
可以嘗試動手試一試,有什么疑問 !可隨時交流,有問必答 。
margin 縱向重疊(合并)問題
元素垂直排列時,第一個元素的下外邊距與第二個元素的上外邊距會發(fā)生合并,合并后的間距就是兩者中最大的那個值。
<style>
.box{
margin-top:10px;/*上外邊距*/
margin-bottom:20px;/*下外邊距*/
height: 20px;
background-color:skyblue;
}
</style>
<body>
<div class="box">item1</div>
<div class="box"></div>
<div class="box"></div>
<div class="box">item4</div>
</body>
答案:
解析:item1 與 item4 之間的間距為 3個下外邊距大小+2個盒子高度=20*3+20*2=100px
<style>
.box{
margin-top:10px;
margin-bottom:20px;
background-color:skyblue;
}
</style>
<body>
<div class="box">item1</div>
<div class="box"></div>
<div class="box"></div>
<div class="box">item4</div>
</body>
答案: item1與item4之間間距為 20px
解析:因為中間兩個box中沒有內(nèi)容也沒有邊框線,所以外邊距會一直重疊合并,所以最后item1和item4之間距離只有一個下外邊距的大小
margin 穿透問題
當(dāng)一個元素包含在另一個元素中時,如果父元素沒有設(shè)置內(nèi)邊距或邊框把外邊距分隔開,它們的上或下外邊距也會發(fā)生合并。
<style>
body{
margin:0;
padding:0;
}
.container{
width:300px;
height: 300px;
background-color: salmon;
margin-top:100px;/*與瀏覽器頂部的距離*/
border:5px solid blue;
}
.container .item{
width:200px;
height: 200px;
background-color: skyblue;
margin-top:50px;/*因為container中加了border邊框,所以這里的外邊距不會穿透合并*/
}
.container .item .box{
width:100px;
height: 100px;
background-color: bisque;
margin-top:10px;/*item沒有加邊框線,內(nèi)邊距和其它內(nèi)容,所以外邊距會發(fā)生穿透合并*/
border:5px solid red;
}
</style>
<body>
<div class="container">
<div class="item">
<div class="box"></div>
</div>
</div>
</body>
答案: 100px 、155px、155px
解析:
.container與瀏覽器頂部距離是100px,
.item與瀏覽器頂部距離100px + 5px+50px=155px
.box與瀏覽器頂部距離:100px+5px+50px=155px
margin-left 設(shè)置負(fù)值,元素向左移動
margin-right 設(shè)置負(fù)值,自身不受影響,右邊元素向左移動
margin-top設(shè)置負(fù)值,元素向上移動
margin-bottom 設(shè)置負(fù)值,自身不受影響,下方元素向上移動
<style>
body{
margin:0;
}
.container{
width:500px;
height:200px;
padding:20px 0px;
border:5px solid #ddd;
margin:0px auto;
}
.container .common{
width:200px;
height: 200px;
float: left;
}
.container .box1{
background-color: skyblue;
/* margin-left:-100px; 元素自身向左移動,右邊的元素也會受影響*/
margin-right:-100px;/*元素自身不受影響,右邊元素向左移動*/
}
.container .box2{
background-color: tomato;
}
</style>
<body>
<div class="container">
<div class="box1 common"></div>
<div class="box2 common"></div>
</div>
</body>
當(dāng).container .box1中margin-left:-100px;時,如:圖1
當(dāng).container .box1中 margin-right:-100px;時,如:圖2
當(dāng).container .box1設(shè)置margin-left:-100px;和margin-right:-100px時,如:圖3
<style>
body{
margin:0;
}
.container{
height: 500px;
width: 200px;
padding:0px 20px;
border:5px solid #ddd;
margin-top:100px;
}
.container .common{
width:200px;
height: 200px;
}
.container .box1{
background-color: skyblue;
/*margin-top:-100px;元素向上移動,下方元素也會受影響*/
margin-bottom:-100px;/*自身不受影響,下方元素向上移動*/
}
.container .box2{
background-color: rgba(0,0,255,0.5);
}
</style>
<body>
<div class="container">
<div class="box1 common"></div>
<div class="box2 common"></div>
</div>
</body>
當(dāng).container .box1中margin-top:-100px時,如:圖 1
當(dāng).container .box1中margin-bottom:-100px時,如:圖 2
當(dāng).container .box1中同時設(shè)置margin-top:-100px; 和margin-bottom:-100px;時,如:圖 3
這種布局的優(yōu)點:
中間一欄內(nèi)容最重要,最先加載和渲染,同時對搜索引擎優(yōu)化最利。
兩邊內(nèi)容固定,中間內(nèi)容自適應(yīng)
<style>
body{
margin:0;
/*核心代碼*/
min-width: 650px;/*當(dāng)頁面寬度不夠時,出現(xiàn)滾動條而不會造成布局錯亂*/
}
.clearfix::after{
display: block;
content: "";
clear: both;
}
.fl{/*核心代碼*/
float:left;/*三個盒子一定要添加浮動*/
}
.header{
height: 100px;
background-color: tomato;
}
.container{
padding-left:200px;/*左邊預(yù)留200px位置 用來放left*/
padding-right:250px;/*右邊預(yù)留200px位置 用來放right*/
}
.container .center{
width:100%;/*自適應(yīng)container的寬度,實現(xiàn)自適應(yīng)縮放*/
height: 500px;
background-color: skyblue;
}
.container .left{
width:200px;
height: 500px;
background-color:cadetblue;
/*核心代碼*/
margin-left:-100%;/*盒子向左移,因為加了浮動,所以會移動到上一行的最左邊*/
position: relative;/*利用相對定位,再把盒子往左移200px就占據(jù)了最左邊預(yù)留的200px空間*/
left:-200px;
}
.container .right{
width:250px;
height: 500px;
background-color:aquamarine;
/*核心代碼*/
margin-right:-250px;/*加上這個代碼,相當(dāng)于right沒有一點寬度,就會移動到上的最右邊位置*/
}
.footer{
height: 100px;
background-color: #000;
}
</style>
<body>
<div class="header">頭部</div>
<div class="container clearfix">
<div class="center fl">中間</div>
<div class="left fl">左邊</div>
<div class="right fl">右邊</div>
</div>
<div class="footer">底部</div>
</body>
這種布局的優(yōu)點:
中間一欄內(nèi)容最重要,最先加載和渲染,同時對搜索引擎優(yōu)化最利。
兩邊內(nèi)容固定,中間內(nèi)容自適應(yīng)
<style>
body{
margin:0;
}
.fl{/*核心代碼*/
float: left;/*一定要添加浮動*/
}
.main{
background-color: #ddd;
width:100%;
}
.main .main-content{
background-color: skyblue;
height: 300px;
/*核心代碼*/
margin:0 200px 0 200px;/*盒子左右兩邊余留200px,分別給left和right來占用*/
}
.left{
width: 200px;
height: 300px;
background-color: coral;
/*核心代碼*/
margin-left:-100%;/*往左移動瀏覽器的寬度,最后移動到上一行的最左邊*/
}
.right{
width: 200px;
height: 300px;
background-color: tomato;
/*核心代碼*/
margin-left:-200px;/*相當(dāng)于自身寬度為0了,因為加了浮動,然后就顯示在了上一行的最右邊*/
}
</style>
<body>
<div class="main fl">
<div class="main-content">中間</div>
</div>
<div class="left fl">左邊</div>
<div class="right fl">右邊</div>
</body>
為幫助到一部分同學(xué)不走彎路,真正達(dá)到一線互聯(lián)網(wǎng)大廠前端項目研發(fā)要求,首次實力寵粉,打造了《30天挑戰(zhàn)學(xué)習(xí)計劃》,內(nèi)容如下:
HTML/HTML5,CSS/CSS3,JavaScript,真實企業(yè)項目開發(fā),云服務(wù)器部署上線,從入門到精通
共4大完整的項目開發(fā) !一行一行代碼帶領(lǐng)實踐開發(fā),實際企業(yè)開發(fā)怎么做我們就是怎么做。從學(xué)習(xí)一開始就進(jìn)入工作狀態(tài),省得浪費時間。
從學(xué)習(xí)一開始就同步使用 Git 進(jìn)行項目代碼的版本的管理,Markdown 記錄學(xué)習(xí)筆記,包括真實大廠項目的開發(fā)標(biāo)準(zhǔn)和設(shè)計規(guī)范,命名規(guī)范,項目代碼規(guī)范,SEO優(yōu)化規(guī)范
從藍(lán)湖UI設(shè)計稿 到 PC端,移動端,多端響應(yīng)式開發(fā)項目開發(fā)
這些內(nèi)容在《30天挑戰(zhàn)學(xué)習(xí)計劃》中每一個細(xì)節(jié)都有講到,包含視頻+圖文教程+項目資料素材等。只為實力寵粉,真正一次掌握企業(yè)項目開發(fā)必備技能,不走彎路 !
過程中【不涉及】任何費用和利益,非誠勿擾 。
如果你沒有添加助理老師微信,可以添加下方微信,說明要參加30天挑戰(zhàn)學(xué)習(xí)計劃,來自頭條號!老師會邀請你進(jìn)入學(xué)習(xí),并給你發(fā)放相關(guān)資料
30 天挑戰(zhàn)學(xué)習(xí)計劃 Web 前端從入門到實戰(zhàn) | arry老師的博客-艾編程
目中有時候會遇到這個問題:一行有3個div,希望這3個div平分屏幕寬度,并且高度等于寬度。
第一個問題:平分屏幕寬度
可以對div設(shè)置百分比寬度,而不是直接用px寬度,這里用到了響應(yīng)式設(shè)計的思想,可以參考這篇文章:自適應(yīng)網(wǎng)頁設(shè)計(Responsive Web Design)
第二個問題:動態(tài)設(shè)置高度和寬度一致
有兩種方法,一種是用js動態(tài)設(shè)置,一種是直接用CSS設(shè)置
先看下html代碼
<ul>
<li class="container">
<div class="dummy">
</div>
<div class="element">
some text
</div>
</li>
<li class="container">
<div class="dummy">
</div>
<div class="element">
some text
</div>
</li>
<li class="container">
<div class="dummy">
</div>
<div class="element">
some text
</div>
</li>
</ul>
公用的CSS
ul,li{
list-style: none;
}
* {
margin: 0;
padding: 0;
outline: 0
}
body {
margin: 0;
padding: 0;
-webkit-appearance: none;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 16px;
}
ul{
margin:10px;
}
.container {
display: inline-block;
position: relative;
width: 32%;
text-align: center;
}
用js動態(tài)設(shè)置
var cw = $('.dummy').width();
$('.dummy').css({'height':cw+'px'});
$(window).resize(function() {
var cw = $('.dummy').width();
$('.dummy').css({'height':cw+'px'});
});
用CSS設(shè)置
.dummy {
padding-top: 100%; /* 1:1 aspect ratio */
width: 100%;
background: #333333;
}
CSS設(shè)置padding-top的原理:Use CSS to Specify the Aspect Ratio of a Fluid Element
/———————————————————
然后嘗試對圖片設(shè)置高度等于動態(tài)寬度
js方法很簡單,跟上面的方法基本相同
<ul>
<li class="container">
<img src="images/test_1.jpg"/>
<div class="element">
some text
</div>
</li>
<li class="container">
<img src="images/test_2.jpg"/>
<div class="element">
some text
</div>
</li>
<li class="container">
<img src="images/test_3.jpg"/>
<div class="element">
some text
</div>
</li>
</ul>
.container {
display: inline-block;
position: relative;
width: 32%;
text-align: center;
}
.container img{
width: 100%;
height:100%;
}
var cw = $('.dummy').width();
$('.dummy').css({'height':cw+'px'});
$(window).resize(function() {
var cw = $('.dummy').width();
$('.dummy').css({'height':cw+'px'});
});
CSS方法
<ul>
<li class="container">
<div class="dummy">
</div>
<div class="element">
some text
</div>
</li>
<li class="container">
<div class="dummy">
</div>
<div class="element">
some text
</div>
</li>
<li class="container">
<div class="dummy">
</div>
<div class="element">
some text
</div>
</li>
</ul>
.container {
display: inline-block;
position: relative;
width: 32%;
text-align: center;
}
.dummy{
padding-top: 100%; /* 1:1 aspect ratio */
width: 100%;
background:url(images/test_3.jpg) no-repeat;
-webkit-background-size: 100%;
background-size: 100%;
}
通過設(shè)置background可以實現(xiàn)。
div包含img的方法沒有試驗成功,以后繼續(xù)嘗試
/————————————-
還有一個問題,怎么設(shè)置div和img之間的padding,又能保證div寬度是屏幕寬度的三分之一?
文來源于:程序員成長指北;作者:去偽存真
如有侵權(quán),聯(lián)系刪除
最近在項目中要實現(xiàn)一個拖拽頭像的移動效果,一直對JS Dom拖拽這一塊不太熟悉,甚至在網(wǎng)上找一個示例,都看得云里霧里的,發(fā)現(xiàn)遇到最大的攔路虎就是JS Dom各種各樣的距離,讓人頭暈眼花,看到一個距離屬性,大腦中的印象極其模糊,如同有一團(tuán)霧一樣,不知其確切含義。果然是基礎(chǔ)不牢,地動山搖。今天決心夯實一下基礎(chǔ),親自動手驗證一遍dom各種距離的含義。
下面我們進(jìn)入正題, 筆者不善于畫圖, 主要是借助瀏覽器開發(fā)者工具,通過獲取的數(shù)值給大家說明一下各種距離的區(qū)別。
本打算用截圖軟件丈量尺寸,結(jié)果發(fā)現(xiàn)截圖軟件顯示的屏幕寬度與瀏覽器開發(fā)者工具獲取的寬度不一致,這是為什么呢?
這是怎么回事?原來在PC端,也存在一個設(shè)備像素比的概念。它告訴瀏覽器一個css像素應(yīng)該使用多少個物理像素來繪制。要說設(shè)備像素比,得先說一下像素和分辨率這兩個概念。
設(shè)備像素比的定義是:
window.devicePixelRatio =顯示設(shè)備物理像素分辨率顯示設(shè)備CSS像素分辨率\frac{顯示設(shè)備物理像素分辨率}{顯示設(shè)備CSS像素分辨率}顯示設(shè)備CSS像素分辨率顯示設(shè)備物理像素分辨率
根據(jù)設(shè)備像素比的定義, 如果知道顯示設(shè)備橫向的css像素值,根據(jù)上面的公式,就能計算出顯示設(shè)備橫向的物理像素值。
顯示設(shè)備寬度物理像素值 = window.screen.width * window.devicePixelRatio;
設(shè)備像素比在我的筆記本電腦上顯示的數(shù)值是1.25, 代表一個css邏輯像素對應(yīng)著1.25個物理像素。
我前面的公式計算了一下,與截圖軟件顯示的像素數(shù)值一致。這也反過來說明,截圖軟件顯示的是物理像素值。
發(fā)現(xiàn)是由筆記本電腦屏幕的縮放設(shè)置決定的,如果設(shè)置成100%, 此時window.screen.width與筆記本電腦的顯示器分辨率X軸方向的數(shù)值一致,都是1920(如右側(cè)圖所示), 此時屏幕上的字會變得比較小,比較傷視力。
邏輯像素是為了解決屏幕相同,分辨率不同的兩臺顯示設(shè)備, 顯示同一張圖片大小明顯不一致的問題。比如說兩臺筆記本都是15英寸的,一個分辨率是1920*1080,一個分辨率是960*540, 在1920*1080分辨率的設(shè)備上,每個格子比較小,在960*540分辨率的設(shè)備上,每個格子比較大。一張200*200的圖片,在高分率的設(shè)備上看起來會比較小,在低分辨率的設(shè)備上,看起來會比較大。觀感不好。為了使同樣尺寸的圖片,在兩臺屏幕尺寸一樣大的設(shè)備上,顯示尺寸看起來差不多一樣大,發(fā)明了邏輯像素這個概念。
規(guī)定所有電子設(shè)備呈現(xiàn)的圖片等資源尺寸統(tǒng)一用邏輯像素表示。然后在高分辨率設(shè)備上,提高devicePixelRatio, 比如說設(shè)置1920*1080設(shè)備的devicePixelRatio(dpr)等于2, 一個邏輯像素占用兩個格子,在低分辨率設(shè)備上,比如說在960*540設(shè)備上設(shè)置dpr=1, 一個css邏輯像素占一個格子, 這樣兩張圖片在同樣的設(shè)備上尺寸大小就差不多了。通常設(shè)備上的邏輯像素是等于物理像素的,在高分辨率設(shè)備上,物理像素是大于邏輯像素數(shù)量的。由此也可以看出,物理像素一出廠就是固定的,而設(shè)備的邏輯像素會隨著設(shè)備像素比設(shè)置的值不同而改變。但圖片的邏輯像素值是不變的。
差別是很容易辨別的,如下圖所示:
如下圖所示,截圖時在未把網(wǎng)頁可視區(qū)域的滾動條高度計算在內(nèi)的條件下, 截圖工具顯示的網(wǎng)頁可視區(qū)域高度是168, 瀏覽器顯示的網(wǎng)頁可視區(qū)域的高度是167.5, 誤差0.5,由于截圖工具是手動截圖,肯定有誤差,結(jié)果表明,網(wǎng)頁可視區(qū)域的高度 不包括滾動條高度。寬度同理。
屏幕寬高是個固定值,網(wǎng)頁可視區(qū)域?qū)捀邥艿娇s放窗口影響。
屏幕可用高度=屏幕高度-屏幕下方任務(wù)欄的高度,也就是:
window.screen.availHeight = window.screen.height - 系統(tǒng)任務(wù)欄高度
scrollWidth(滾動寬度,包含滾動條的寬度)=scrollLeft(左邊卷去的距離)+clientWidth(可見部分寬度);
// 同理
scrollHeight(滾動高度,包含滾動條的高度)=scrollTop(上邊卷去的距離)+clientHeight(可見部分高度);
需要注意的是,上面這三個屬性,都取的是溢出元素的父級元素屬性。而不是溢出元素本身。本例中溢出元素是body(document.body),其父級元素是html(document.documentElement)。另外,
溢出元素的寬度(document.body.scrollWidth)=父級元素的寬度(document.documentElement.scrollWidth) - 滾動條的寬度(在谷歌瀏覽器上滾動條的寬度是19px)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<title>JS Dom各種距離</title>
<style>
html, body {
margin: 0;
}
body {
width: 110%;
border: 10px solid blue;
}
.rect {
height: 50px;
background-color: green;
}
</style>
</head>
<body>
<div id="rect" class="rect"></div>
</body>
</html>
從下圖可以看出:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<title>JS Dom各種距離</title>
<style>
div {
border: 1px solid #000;
width: 200px;
height: 600px;
padding: 10px;
background-color: green;
margin: 10px;
}
</style>
</head>
<body>
<div class="rect"> 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
</div>
</body>
<script>
</script>
</html>
offsetWidth和clientWidth的共同點是都包括 自身寬度+padding , 不同點是offsetWidth包含border。
如下圖所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<title>JS Dom各種距離</title>
<style>
div {
border: 1px solid #000;
width: 200px;
height: 100px;
padding: 10px;
background-color: green;
margin: 10px;
}
</style>
</head>
<body>
<div class="rect">111111111111111111111111111111111111111111111111</div>
</body>
<script>
</script>
</html>
代碼如下,給rect元素添加一個mousedown事件,打印出事件源的各種位置值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<title>JS Dom各種距離</title>
<style>
html,
body {
margin: 0;
}
body {
width: 200px;
padding: 10px;
border: 10px solid blue;
}
.rect {
height: 50px;
background-color: green;
}
</style>
</head>
<body>
<div id="rect" class="rect"></div>
</body>
<script>
const rectDom = document.querySelector('#rect');
rectDom.addEventListener('mousedown', ({ offsetX, offsetY, clientX, clientY, pageX, pageY, screenX, screenY }) => {
console.log({ offsetX, offsetY, clientX, clientY, pageX, pageY, screenX, screenY });
})
</script>
</html>
我們通過y軸方向的高度值,了解一下這幾個屬性的含義。 綠色塊的高度是50px, 我們找個特殊的位置(綠色塊的右小角)點擊一下,如下圖所示:
所以它們各自的含義,就很清楚了。
事件源屬性 | 表示的距離 |
event.offsetX、event.offsetY | 鼠標(biāo)相對于事件源元素(srcElement)的X,Y坐標(biāo), |
event.clientX、event.clientY | 鼠標(biāo)相對于瀏覽器窗口可視區(qū)域的X,Y坐標(biāo)(窗口坐標(biāo)),可視區(qū)域不包括工具欄和滾動偏移量。 |
event.pageX、event.pageY | 鼠標(biāo)相對于文檔坐標(biāo)的x,y坐標(biāo),文檔坐標(biāo)系坐標(biāo) = 視口坐標(biāo)系坐標(biāo) + 滾動的偏移量 |
event.screenX、event.screenY | 鼠標(biāo)相對于用戶顯示器屏幕左上角的X,Y坐標(biāo) |
我們點擊下圖綠色塊的右下角,把pageX和clientX值打印出來。如下圖所示:
從下圖可以看出,上下左右這四個屬性,都是相對于瀏覽器可視區(qū)域左上角而言的。
從下圖可以看出,當(dāng)有滾動條出現(xiàn)的時候,right的值是359.6,而不是360+156(x軸的偏移量), 說明通過getBoundingClientRect獲取的屬性值是不計算滾動偏移量的,是相對瀏覽器可視區(qū)域而言的。
MouseEvent.movementX/movementX是一個相對偏移量。返回當(dāng)前位置與上一個mousemove事件之間的水平/垂直距離。以當(dāng)前位置為基準(zhǔn), 鼠標(biāo)向左移動, movementX就是負(fù)值,向右移動,movementX就是正值。鼠標(biāo)向上移動,movementY就是負(fù)值,向下移動,movementY就是正值。數(shù)值上,它們等于下面的計算公式。 這兩個值在設(shè)置拖拽距離的時候高頻使用,用起來很方便。
curEvent.movementX = curEvent.screenX - prevEvent.screenX;
curEvent.movementY = curEvent.screenY - prevEvent.screenY;
mouse事件相對簡單,只有mousedown(開始),mousemove(移動中),mouseup(結(jié)束)三種。與之對應(yīng)的移動端事件是touch事件,也是三種touchstart(手指觸摸屏幕), touchmove(手指在屏幕上移動), touchend(手指離開屏幕)。
相對而言, drag事件就要豐富一些。
事件名 | 觸發(fā)時機(jī) | 觸發(fā)次數(shù) |
dragstart | 拖拽開始時觸發(fā)一次 | 1 |
drag | 拖拽開始后反復(fù)觸發(fā) | 多次 |
dragend | 拖拽結(jié)束后觸發(fā)一次 | 1 |
事件名 | 觸發(fā)時機(jī) | 觸發(fā)次數(shù) |
dragenter | 被拖拽元素進(jìn)入目標(biāo)時觸發(fā)一次 | 1 |
dragover | 被拖拽元素在目標(biāo)容器范圍內(nèi)時反復(fù)觸發(fā) | 多次 |
drop | 被拖拽元素在目標(biāo)容器內(nèi)釋放時(前提是設(shè)置了dropover事件) | 1 |
想要移動一個元素,該如何選擇這兩種事件類型呢? 選擇依據(jù)是:
類型 | 選擇依據(jù) |
mouse事件 | 1. 要求絲滑的拖拽體驗 2. 無固定的拖拽區(qū)域 3. 無需傳數(shù)據(jù) |
drag事件 | 1. 拖拽區(qū)域有范圍限制 2. 對拖拽流暢性要求不高 3. 拖拽時需要傳數(shù)據(jù) |
光說不練假把式, 掃清了學(xué)習(xí)障礙后,讓我們自信滿滿地寫一個兼容PC端和移動端的拖動效果。不積跬步無以至千里,幻想一口吃個胖子,是不現(xiàn)實的。這一點在股市上體現(xiàn)的淋漓盡致。都是有耐心的人賺急躁的人的錢。所以,要我們沉下心來,打牢基礎(chǔ),硬骨頭啃一點就會少一點,步步為營,穩(wěn)扎穩(wěn)打,硬骨頭也會被啃成渣。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>移動小鳥</title>
<style>
body {
margin: 0;
font-size: 0;
position: relative;
height: 100vh;
}
.bird {
position: absolute;
width: 100px;
height: 100px;
cursor: grab;
z-index: 10;
}
</style>
</head>
<body>
<img class="bird" src="./bird.png" alt="" />
</body>
<script>
let evtName = getEventName();
// 鼠標(biāo)指針相對于瀏覽器可視區(qū)域的偏移
let offsetX = 0, offsetY = 0;
// 限制圖片可以X和Y軸可以移動的最大范圍,防止溢出
let limitX = 0, limitY = 0;
// 確保圖片加載完
window.onload = () => {
const bird = document.querySelector(".bird");
const { width, height } = bird;
limitX = document.documentElement.clientWidth - width;
limitY = document.documentElement.clientHeight - height;
bird.addEventListener(evtName.start, (event) => {
// 監(jiān)聽鼠標(biāo)指針相對于可視窗口移動的距離
// 注意移動事件要綁定在document元素上,防止移動過快,位置丟失
document.addEventListener(evtName.move, moveAt);
});
// 鼠標(biāo)指針停止移動時,釋放document上綁定的移動事件
// 不然白白產(chǎn)生性能開銷
document.addEventListener(evtName.end, () => {
document.removeEventListener(evtName.move, moveAt);
})
// 移動元素
function moveAt({ movementX, movementY }) {
const { offsetX, offsetY } = getSafeOffset({ movementX, movementY });
window.requestAnimationFrame(() => {
bird.style.cssText = `left:${offsetX}px;top:${offsetY}px;`;
});
};
};
// 獲取安全的偏移距離
const getSafeOffset = ({ movementX, movementY }) => {
// //距上次鼠標(biāo)位置的X,Y方向的偏移量
offsetX += movementX;
offsetY += movementY;
// 防止拖拽元素被甩出可視區(qū)域
if (offsetX > limitX) {
offsetX = limitX;
}
if (offsetX < 0) {
offsetX = 0;
}
if (offsetY > limitY) {
offsetY = limitY;
}
if (offsetY < 0) {
offsetY = 0;
}
// console.log({ movementX, movementY, offsetX, offsetY });
return { offsetX, offsetY };
}
// 區(qū)分是移動端還是PC端移動事件
function getEventName() {
if ("ontouchstart" in window) {
return {
start: "touchstart",
move: "touchmove",
end: "touchend",
};
} else {
return {
start: "pointerdown",
move: "pointermove",
end: "pointerup",
};
}
}
</script>
</html>
在chrome瀏覽器上發(fā)現(xiàn)一個奇怪的現(xiàn)象,設(shè)置的border值是整數(shù),計算出來的值卻帶有小數(shù)
而當(dāng)border值是4的整數(shù)倍的時候,計算值是正確的
看了這篇文章[5]解釋說,瀏覽器可能只能渲染具有整數(shù)物理像素的border值,不是整數(shù)物理像素的值時,計算出的是近似border值。這個解釋似乎講得通,在設(shè)備像素比是window.devicePixelRatio=1.25的情況下, 1px對應(yīng)的是1.25物理像素, 1.25*4的倍數(shù)才是整數(shù),所以設(shè)置的邏輯像素是4的整數(shù)倍數(shù),顯示的渲染計算值與設(shè)置值一致,唯一讓人不理解的地方,為什么padding,margin,width/height卻不遵循同樣的規(guī)則。
[1] https://baike.baidu.com/item/%E6%98%BE%E7%A4%BA%E5%88%86%E8%BE%A8%E7%8E%87/3431933?fromModule=lemma_inlink
[2] https://baike.baidu.com/item/%E5%9B%BE%E5%83%8F%E5%88%86%E8%BE%A8%E7%8E%87/872374?fromModule=lemma_inlink
[3] https://baike.baidu.com/item/%E6%89%93%E5%8D%B0%E5%88%86%E8%BE%A8%E7%8E%87/9560832?fromModule=lemma_inlink
[4] https://baike.baidu.com/item/%E6%89%AB%E6%8F%8F%E5%88%86%E8%BE%A8%E7%8E%87/7122498?fromModule=lemma_inlink
[5] https://www.w3.org/TR/CSS22/cascade.html#specified-value
?
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。