# 動態圖片之新增、刪除與排序
### **撰寫程式:HTML | CSS | JS**
* [codepen](https://codepen.io/liu_0821/pen/WNaYrEq)
* [Medium](https://medium.com/@LindaLiu0821/%E5%9C%96%E7%89%87%E5%8B%95%E6%85%8B%E6%96%B0%E5%A2%9E-%E5%88%AA%E9%99%A4%E8%88%87%E6%8E%92%E5%BA%8F-b41a053e760e)

## HTML
1. ##### HTML中的標籤`label`中的`for`,對應`input`的`Id`屬性。
```
<div class = "main" id = "inBox">
<label for="addImage" class = "addImage" ></label>
<input type="file" id="addImage" accept="image/*">
<div class="Box">
<div class="ImgBox">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQvi6Ul_hZD5W9dIpr8NQF13T7uybwNHtBwyw&usqp=CAU" alt="">
</div>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-dash-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM4.5 7.5a.5.5 0 0 0 0 1h7a.5.5 0 0 0 0-1h-7z"/>
</svg>
</div>
</div>
```
## CSS 擷取片段
> ###### 大致上比較著需要注意的是`position`的使用,與`object-fit`圖片的區塊填滿設定。
```
// 顯示圖片樣式
.Box{
position: relative;
height: 150px;
border: 1px solid #eeeeee;
margin: .2rem .5rem;
}
.ImgBox{
width: 150px;
height: 100%;
overflow: hidden;
position: relative; // 滑鼠光標樣式
cursor: move;
}
.ImgBox > img{
position: absolute;
top:50%;
left:50%;
display:block;
max-width: 150px;
max-height: 100%;
transform:translate(-50%,-50%);
object-fit: contain;
}
// 新增圖片樣式
.addImage{
cursor: pointer;
width: 150px;
height: calc(100% / 3.3);
background-color: #eeeeee;
display: flex;
align-items: center;
justify-content: center;
margin: .2rem .5rem;
font-family:'Noto Sans TC';
font-weight:700;
}
.addImage::before{
font-family:fantasy;
content:"➕";
font-weight:900;
}
input[type='file']{
display:none; // 使用者點擊label,所以這個隱藏起來就好~
}
```
> ###### 動畫效果
```
.animationShake{
animation: shake 800ms ease-in-out;
animation-iteration-count:infinite;
background-color: #eeeeee;
}
@keyframes shake {
10%,90%{
transform: translate3d(-1px,0,0);
}
20%,80%{
transform: translate3d(2px,0,0);
}
30%,70%{
transform: translate3d(-4px,0,0);
}
40%,60%{
transform: translate3d(4px,0,0);
}
50%{
transform: translate3d(-4px,0,0);
}
}
```
## JS
> ###### 點選要上傳的圖片
```
$("label[for='addImage']").on('click', function (e) {
// 使用one就只會執行一次
$('#addImage').one('change', function () {
let fr = new FileReader();//建立FileReader物件
let file = this.files[0];//將上傳檔案轉換為base64字串
fr.readAsDataURL(file);// 使用 readAsDataURL 將圖片轉成 Base64
fr.onload = function (e) {
runImg(e.target.result);
};
});
});
```
> ###### 新增`img`的標籤
```
function runImg(data) {
$('.main').append(
`
<div class="Box">
<div class="ImgBox">
<img src="`+data+`" alt="">
</div>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-dash-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM4.5 7.5a.5.5 0 0 0 0 1h7a.5.5 0 0 0 0-1h-7z"/>
</svg>
</div>
`
);
}
```
> ###### 移除`img`的標籤
```
function removeBtn() {
$(".bi.bi-dash-circle-fill").on('click', function (e) {
let dom = $(e.target).parent().parent();
if($(dom).attr("class")==="Box"){
$(dom).remove();
}
});
}
```
> ###### 排序( 圖與圖之間交換 )
```
function moveImage(){
let ImgBox = $(".Box");
let inBox = document.getElementById("inBox");
console.log(ImgBox)
let container=null;
// 給每個div去綁定事件
for(let i=0;i<ImgBox.length;i++){
// ondragstart 拖動執行
ImgBox[i].ondragstart=function(){
container=this;
}
// ondragover 拖動到目標放置
// ---> 在拖動時仍然保持抖動的動畫效果
ImgBox[i].ondragover=function(){
event.preventDefault();
$(this).addClass('animationShake');
}
// ondragenter 拖動進入範圍時觸發
// ---> 保持只有被選取到的有效果
ImgBox[i].ondragenter = function(){
remove();
};
// ondrop 可拖動元素放置在div時執行
// ---> 確定好位置後清除動畫效果
ImgBox[i].ondrop=function(){
if(container!=null&&container!=this){
console.log(this)
let temp=document.createElement("div");
inBox.replaceChild(temp,this); //用新建的div佔據目的位置
inBox.replaceChild(this,container);// 目的div放置在起始位置
inBox.replaceChild(container,temp) // 起始div放置在目的位置
}
remove()
}
}
}
```
> ###### 清除動畫效果
```
function remove(){
let ImgBox =$(".Box");
$.each(ImgBox,function(ins,items){
$(items).removeClass('animationShake');
});
}
```
### 如何避免圖片重複累加?
1. `$('#addImage')`的函式中使用`one`可確保只執行一次,避免重複讀取值。
2. 在`change`中`readAsDataURL`之下加上`$('#addImage').replaceWith('<input type="file" accept="image/*">')`,更新`input`的標籤,確保每次點選都是新的值也不會重複。
3. 在`change`之前,新增`$('#addImage').off('change');`事件移除再讓他重新註冊就可以喽。
---
##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人
##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~