Devcker天天踩坑

日常踩坑紀錄

最近因為公司的專案,需要一個這樣的功能,所以上網找了一下有沒有已經造好的輪子,但是找到的都是要綁其他的套件例如jquery之類的,加上功能都太多,我覺得因為一個小需求就把一整個套件放進來是有點太草率了,所以就試著用原生JS刻一個簡單的出來

成品大概長這樣

See the Pen InputTag by CKR (@kamix) on CodePen.

主要功能就是一個大的輸入框,輸入完成之後按下Enter會產生一個tag TagInput Demo

他的值會是 TEST,TEST2,TEST3,有幾個Tag就會用逗號接起來,點擊tag可以刪掉值,就是一個簡單的功能,需要的朋友可以直接抄codepen的程式碼再自己改一下應該就可以了,如果沒興趣知道實做就可以點上一頁走摟

實作部分

這個的概念很簡單,就是用一個div偽裝成一個大的input,在裡面藏一個沒有邊框的input,然後監聽keyup事件,如果輸入Enter就會建立一個tag的dom放到最前面,同時tag也監聽點擊事件,如果點擊就把自己刪掉這樣

然後就是值的部分會用一個hidden的input存起來,這樣不管是送表單還是取值都可以直接拿hidden input的值去用,我有另外用一個陣列來管理這些值的狀態,每次更新值的時候hidden input的值會更新成這個陣列.join(“,”),這樣後台只要去切到逗號就可以很簡單的取得陣列

1
hidden.value = tmp.join(",")

最外面的偽輸入框

html

1
<div class="tagInput" id="tagInput"></div>

css讓整塊的corsor都是text,完美偽裝input

1
2
3
4
5
6
7
.tagInput {
border: 1px solid #000;
width: 500px;
min-height: 100px;
cursor: text;
padding: 2px;
}

javascript

1
var tagInput = document.getElementById("tagInput")

Input輸入框和放tag的區域

輸入框要分成兩部份,一個是要給使用者輸入用的,一個是隱藏起來存值用的,這邊讓輸入的地方放在tag的後面

html直接放到tagInput的div裡面

1
2
3
4
5
<input class="hidden" type="hidden">
<div class="wrap">
<div class="tags"></div>
<input class="input" type="text">
</div>

css這邊讓input的邊框用不見,這樣看起來就會感覺一整塊外面的div都是輸入框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.wrap {
display: flex;
flex-wrap: wrap;
}

.tags {
display: flex;
flex-wrap: wrap;
font-size: 16px;
}

.tag {
padding: 8px;
border: 1px #666 solid;
color: #666;
border-radius: 20px;
cursor: pointer;
margin-right: 3px;
margin-bottom: 3px;
}

.input {
border: none;
}

js的部分先把這些東西找出來,這樣之後會比較好處理 javascipt

1
2
3
4
5
var input = tagInput.querySelector(".input")
var tags = tagInput.querySelector(".tags")
var hidden = tagInput.querySelector(".hidden")
// 暫存用的陣列
var tmp = []

監聽最外層的click事件

光是讓外層的cursor變成text是不夠的,還要讓他點擊之後會自動focus到真正的input上面

1
2
3
tagInput.addEventListener("click", function() {
input.focus()
})

專門處理Tag新增的方法

把新增Tag上去的Code都整理成一個方法,這樣之後可以方便呼叫,Tag除了被新增上去之後還需要監聽點擊事件,因為我們希望可以再點擊Tag之後將這個值刪掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 方法只需要傳入輸入的值就可以建立一個tag出來
function addTag(value) {
// 建立一個class是tag的div
var dom = document.createElement("div")
dom.classList.add("tag")
// 將丟進來的值給這個tag
dom.innerText = value
// 還需要監聽點擊事件 這樣才可以處理點擊後要刪除自己的部分
dom.addEventListener("click", function(e) {
// 不過這部份等下做處理hidden值的時候再來處理
}
// 新增剛剛建立的tag上去
tags.appendChild(dom)
}

來處理input上面按下Enter的事件

想要的效果是他輸入完成後可以按下Enter送出,並且會增加一個Tag,所以監聽input的keyup事件,並判斷他按的是Enter

1
2
3
4
5
6
7
8
9
10
input.addEventListener("keyup", function(e) {
var keycode = e.keyCode
// 13是Enter的keycode
if(keycode == 13 && input.value) {
// 這邊要處理新增tag的部分 所以直接呼叫剛剛寫的新增tag的方法 並且把使用者現在打的值傳過去
addTag()
// 新增完之後把舊的值去掉 不然體驗上會怪怪的
input.value = ""
}
})

到這邊你會發現功能好像快完成了,已經看起來可以運行了,但是還沒有因為最重要存值的部分還沒用,這部份沒有用上去,你怎麼去編輯這個input都沒用

處理hidden input的值

一開始的時候我有宣告一個tmp的變數,現在要用它來當hidden input跟tag之間的橋樑

1
var tmp = []

這邊新增一個方法是讓hidden從tmp取值變成字串

1
2
3
4
5
6
7
8
// 名字我不知道怎麼取所以就叫做load 這個名字可以自己取 或者不要包成方法 自己手動加在要更新值的地方也可以 包成方法是我自己的習慣而已
function load() {
// 將hidden的值更新成tmp.join(",")
// 這樣子如果tag有三個分別是 TEST1 TEST2 TEST3的話那hidden的值會變成TEST1,TEST2,TEST3
hidden.value = tmp.join(",")
// 加個console.log檢查更新有沒有成功
console.log("hidden input vlaue: ", hidden.value)
}

Ok有了這個方法之後,我們就可以來修改剛剛說要來處理的地方

1
2
3
4
5
6
7
8
9
10
11
12
dom.addEventListener("click", function(e) {
// 找出這個要刪除的tag是第幾個,也從tmp相同的地方刪除值
tags.querySelectorAll(".tag").forEach(function(child, index) {
if(child === dom) {
// 從tmp相同的地方刪除值
tmp.splice(index, 1)
// 更新hidden input的值
load()
}
})
tags.removeChild(dom)
})

完整addTag方法會變成這樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 方法只需要傳入輸入的值就可以建立一個tag出來
function addTag(value) {
// 建立一個class是tag的div
var dom = document.createElement("div")
dom.classList.add("tag")
// 將丟進來的值給這個tag
dom.innerText = value
// 還需要監聽點擊事件 這樣才可以處理點擊後要刪除自己的部分
dom.addEventListener("click", function(e) {
tags.querySelectorAll(".tag").forEach(function(child, index) {
if(child === dom) {
tmp.splice(index, 1)
load()
}
})
tags.removeChild(dom)
})
// 新增剛剛建立的tag上去
tags.appendChild(dom)
}

再來是處理input監聽Enter事件那邊

1
2
3
4
5
6
7
8
if(keycode == 13 && input.value) {
addTag(input.value)
// 新增的時候也對tmp新增
tmp.push(input.value)
// tmp新增完之後也更新hidden input的值
load()
input.value = ""
}

整段code會變成這樣

1
2
3
4
5
6
7
8
9
input.addEventListener("keyup", function(e) {
var keycode = e.keyCode
if(keycode == 13 && input.value) {
addTag(input.value)
tmp.push(input.value)
load()
input.value = ""
}
})

最後的小步驟

加完上面的處理之後,整個邏輯就完成了,現在剩下要記得幫input加上id或name,如果你是要放在表單一起傳的那就加上name,如果是純粹要用js取值的話,可以加上id或name都可以

結論

大概js花不到50行就可以簡單的實現tag input,當然像這樣寫要建立好幾個tag input是很麻煩的事情,所以可以包裝一下變成可以複用的元件,當然不想這麼麻煩我是建議可以直接用別人寫好的輪子

之前就因為家裡面的電燈開關會導致我的螢幕會閃黑,長期下來真的不是辦法,所以我上網找了一下原因跟解法,發現可能是家裡市電老舊所以可能電流不穩所導致的,後來就上網找了一下解決方法,發現可以買穩壓器來解決這問題,我主要是要插螢幕用的,所以我就買了比較便宜1KVA的穩壓器

上網挑了一下就看到這款正在特價,所以就買了這款回家試試看了

【【FT飛碟】 1KVA 三段全電子式穩壓器

【FT飛碟】 1KVA 三段全電子式穩壓器

下單之後,貨很快就到了,穩壓器還滿重的,應該有1公斤以上,感覺比我的筆電還要重 FT飛碟 1KVA 三段全電子式穩壓器 包裝

馬上把他打開來看,裡面有說明書,保固卡,還有就是本體 FT飛碟 1KVA 三段全電子式穩壓器 開箱

拆掉塑膠袋之後 本體大概長這樣 FT飛碟 1KVA 三段全電子式穩壓器

他有8個插座可以用 分別是四個穩壓跟四個防突波,不過位置還滿近的,大一點的變壓器可能就會佔到兩格位置… FT飛碟 1KVA 三段全電子式穩壓器

然後我馬上把我的設備和螢幕插上去試試看,如圖所示光NS的變壓器就佔了兩格XD,不過這倒是沒關係,還要我沒有太多東西要插,插頭插上去之後他旁邊有個紅色電源開關按一下就啟動了 FT飛碟 1KVA 三段全電子式穩壓器

結論

看別人說如果市電不穩,他燈號會是橘色的,但我這邊都是綠色的感覺市電很穩,試了一下閃黑的問題,結果發現好像不是市電的問題XD,不過心想可以幫忙防突波也是好,畢竟是特價買的,心也沒那麼痛,只是這個閃黑的問題我可能還要另外找到解決辦法了QQ

2020/11/3更新

最後解決了…..我的解決辦法

最近因為想做一些小專案,所以想租vps來玩玩看,後來挑來挑去就選linode來當我第一台vps,用的方案是最便宜的一個月5美金的方案,另外有在namecheap上面買比較便宜的域名來用,不過都買完之後發現問題來了,我並不會dns相關的設定,然後發現這方面文章都是英文居多,所以大概折騰了兩天才搞好,這邊分享一下我自己的作法順便紀錄一下,以免之後忘記

另外有想使用linode但是想玩玩看,還沒註冊的朋友可以用我的邀請連結註冊喔

Linode邀請連結

這篇文章的前提是你已經在namecheap買好了域名,linode那邊也已經設定好的情況下喔,因為linode設定在網路上都找得到所以這邊都不贅述了

Step 1

先進入Linode的Dashboard,左邊選單有一個選項是Domains直接進去 Linode Domains Option

之後右上角的地方有一個Add a Domain一樣直接點下去,他會跑出一個設定的視窗

Linode Domain Setting

Domain那欄填上你買的Domain名稱,例如我在namecheap買的Domain是devcker.xyz那我就填上devcker.xyz

SOA Email Address就填上你常用的email

Add Tags是你有在管理tag的話就自己選自己要放在哪個tag,沒有的話就直接留空

Insert Default Record這項選擇跟圖片上一樣的他會幫你把最常用的DNS設定都設定好

Linode這攔就選你這個Domain是要給哪一台vps用的

Step 2

之後按下確認,就可以看到一整個DNS的設定,其中最重要的就是NS Record,可以看下圖Linode給我了五個name server,而我們只需要把這五個設定到namecheap就行了,之前不知道我還把這頁全部的設定都輸入到namecheap,結果等了一天之後發現失敗了XD

Linode NS Record

到這邊Linode這邊就設定完了,接下來切換到namecheap的頁面

Step 3

一樣先進去namecheap的Dashboard,如果你已經有買Domain應該會出現跟下圖差不多的選項,這邊選MANAGE

namecheap domain

進去之後往下滑到Nameservers的地方,這邊選項原本是Namecheap Basic DNS把它改成Custom DNS,之後下方會出現可以填的選項,這邊把Linode剛剛給的那五個設定上去

namecheap set linode name server

Step 4

如此一來,namecheap跟Linode都設定好了,接下來就是等DNS紀錄傳播開來,大概等個幾小時,如果有設定成功,你用nslookup就會看到網域的ip已經換到你Linode VPS的ip了

我自己因為工作的關係開始在開發chrome的擴充套件,然而因為瀏覽器套件的上下文都在同一個地方,變數都是全域變數,變成我不太好切模組出來,所以我就開始找有沒有用webpack的解法

另外我也有寫用原生的方式載入esm模組的開發方式,也是可以試試看:在瀏覽器插件開發中使用import export來優化架構

用簡單關鍵字去google了一下發現,很多人有同樣的想法,所以都自己造了輪子,我就用了其中一個輪子來造我的套件,我用的是以下這個套件來當輪子

samuelsimoes /chrome-extension-webpack-boilerplate

他看起來符合我的需求,所以我就直接把他clone下來試試看

Step 1

他自己的範例是用yarn,但是我自己是習慣用npm我認為這個應該是沒什麼差別所以如果是用yarn的朋友就直接下指令安裝

yarn

跟我一樣用npm的話,就直接install

npm install

然後看了一下package.json他有兩個指令,一個是start一個是build

1
2
3
4
"scripts": {
"build": "node utils/build.js",
"start": "node utils/webserver.js"
}

start是會開啟hot reload只要你有改檔案,他就會馬上在build一個版本出來,馬上瀏覽器那邊就會重新整理,這正是我所要的開發體驗,而build就只是純粹用production的環境build一個版本而已,這是要發佈的時候才要用,開發的時候用start就可以滿足大部分的需求

Step 2

大概摸了10分鐘的時候發現,我用npm start每次重新build的時候,build出來的manifest.json會不見,天啊,這是一個嚴重的bug,感覺看起來是manifest.json被webpack清除掉了

終於在他的webpack.config.js找到他有用CleanWebpackPlugin在每次build的時候清除資料夾裡面的檔案,雖然他在下面有用CopyWebpackPlugin試圖把manifest.json複製回來,但感覺是時機不對,複製回來後就被刪除了

有可能你在看的同時這個bug已經有被作者修正,我這邊會記錄下我目前的解法

我在CleanWebpackPlugin這邊新增了一個選項,確保manifest.json不會被清除

1
2
3
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['!manifest.json']
}),

Step 3

透過以上的修改,目前看起來開發的流程看起來都正常的工作,接下來我開始測試background跟content的開發的時候發現他預設沒有給content.js,回到github看他的readme才有看到原來是要自己加,照著上面的改法新增修改了之後,content也可以開始跑了

但是在測試content.js的時候又發現了另一個問題,那就是修改content的時候似乎不會載入新的content,不過看起來build的時候新的檔案的確有修改進去才對,這個我並不清楚原因,想說可能是瀏覽器沒有讀取到新的content,所以後來去找了怎麼讓瀏覽器動態去重新載入套件最後找到了這個

andreasvirkus/Extension_reloader.md

我就直接在js資料夾內新增hotReload.js並且在webpack那邊設定build的時候也複製一份過去

在CopyWebpackPlugin這邊的設定再多一個設定

1
2
3
4
5
6
new CopyWebpackPlugin(
[
原本的設定,
{from: "src/js/hotReload.js"}
]
),

最後由於這個專案的background並不是直接用background.js,而是還有用background.html的設定,所以不能直接在manifest.json用這個設定

1
"background": ["reloader.js", "background.js"]

所以我們改成在background.html裡面加上這個,讓background自動去載入這段code

改完之後,看來content的設定也可以自動載入新的了

Step 4

這樣剩下一個問題就是當你瀏覽器啟動著你的套件的時候,你直接去npm start會因為webpack會先清除你的檔案,導致你的瀏覽器會有機會噴他找不到套件的檔案,這邊我就想不到怎麼解了

我目前自己的解法只能每次要npm start的時候先把套件關掉build完成後再打開,但是之後的更改體驗就沒什麼問題了

當兵要帶什麼?

分享一下自己在之前當兵的時候自己帶了什麼跟大家都帶了什麼,還有就是可能不需要帶什麼,這篇會以南訓中心的為主,如果是分發到其他地方的朋友也可以參考一下喔

這篇主要是分享當兵要帶什麼,如果要看心得的可以到這兩篇文章去做參考喔

第一階段心得

第二階段心得

當兵大家都帶什麼書進去看?

推薦要帶的物品

手錶-手錶必帶,帶著不管上課集合還是半夜站夜哨的時候確認時間都超好用,建議帶電子的,晚上驚醒可以看目前時間

自己的內褲-裡面發的內褲很爛,穿自己的最實在

刮鬍刀、指甲剪-這個不用講了,裡面服儀檢查需要用到

藍筆-我進去之後只用過藍筆,雖然裡面會發一支給你,但是很容易不見

三合一沐浴乳-裡面洗澡跟戰爭一樣,洗澡的時候越方便越好

行動電源-手機時間的插座很難搶,自己帶才不用怕沒電(但注意大陸品牌的不要帶進去)

更多的零錢-每一個連的營舍不一定有小蜜蜂,不過都會有飲料販賣機,多帶一些可以投飲料

[adinserter block=”4”] [adinserter block=”9”]

個人認為可以帶的東西

資料袋-裡面其實會給你一個資料袋,但是那個很爛,而且有可能是前一梯用過的,很容易破掉,建議可以買一個防水而且比較堅固的,而且也會比較好拿

-在裡面其實有很多時間可以看書,建議可以帶口袋書放在迷彩口袋,這樣到外面操課下課時可以隨時看,這邊有篇文章介紹裡面大家都帶了什麼書[傳送門]

零食-大概懇親假之後可以帶,在裡面不知道為什麼會很想吃餅乾,防止嘴饞

小型手電筒-通常在裡面要提早起床,所以折蚊帳或做其他事情的時候不能開燈,要做啥事情或上廁所都滿方便的

防水錢包-我這梯有發生過偷竊事件,錢包最好隨身攜帶,洗澡的時候也帶著,另外裡面營站也會賣可以在裡面買就好,再來是裡面也會有一堆奇怪的小卡要你隨身帶著(喝水小卡、防中暑小卡、各種奇怪通報小卡)

自己的衣服-裡面會發軍用內衣,不過放假的時候可以換來穿,不然你會穿之前收假的衣服出去

[adinserter block=”4”] [adinserter block=”9”]

不需要帶的東西

這邊不需要帶的東西都可能是南訓才不需要帶的,所以參考就好

洗碗精、菜瓜布-當兵前看到很多文章都有寫可以帶,但是南訓的餐盤是不用自己洗的,所以不需要帶,就算帶了你也沒機會用

最近在做Telegram的bot,想說可以順便練習azure,所以就去申請了一個azure一年的免費額度來用,整體來說我覺得azure是個不錯的服務,不過價錢相對比較貴也是事實

但是實做到一半的時候發現,當我把程式佈署上去之後,我會看不到線上的log,雖然說程式都是在本地處理完沒問題才會推上去azure佈署,但是萬一出問題,還沒有log可以看,我覺得這會增加很多debug的成本

之後我在vscode的azure介面有看到一個start remote debug

azure remote debug

於是我就直接點下去,點下去之後看了下方的console一直跑出無法連接的訊息

1
[Tunnel] Checking status, body: {"port":2222,"state":"STARTED","canReachPort":false,"msg":"Unable to connect to WebApp"}

之後就直接說失敗 azure remote debug fail

於是我又爬文,原來是要啟動的時候azure的容器會指定一個inspect的port,我們只要把這個port告訴給nodejs讓程式知道說log要到這邊,這樣就可以正常使用remote debug的功能

實際做法

這邊看你是怎麼啟動你的程式,不過作法大同小異,我是用npm run start來啟動,所以我只要在啟動的指令下新增這個參數就可以

1
--inspect=0.0.0.0:$APPSVC_TUNNEL_PORT

至於$APPSVC_TUNNEL_PORT這個參數可以在官方啟動容器的code裡面找到

像我這邊的話就會是這樣

原本:

1
2
3
"scripts": {
"start": "cross-env NODE_ENV=production node ./src/app.js"
}

加上去:

1
2
3
"scripts": {
"start": "cross-env NODE_ENV=production node --inspect=0.0.0.0:$APPSVC_TUNNEL_PORT ./src/app.js"
}

這樣子再把程式部屬上去就可以用remote debug正常看到log了

用一段簡短的js來判斷一個iframe是否有正常載入,如果說iframe是在同網域跑的話,是還好,因為你對於他的控制權更多

但是目前我遇到的是跨網域的問題,因為我是寫瀏覽器套件的時候遇到的,很常要注入iframe結果對方網站有鎖同網域的iframe,這時候就可以用這個判斷如果失敗就隱藏或者是做一些失敗的處理

這個也是我在網路上找了一段時間才找到的,想說做個筆記記錄下來,順便也分享給需要的人

先來直接看code,我這邊直接假設id ifm是一個iframe

1
2
3
4
5
6
7
8
9
// 第一步當然是把它找出來
var iframe = document.getElementById("ifm");
// 綁定onload事件 這樣他載入完之後就可以開始判斷
iframe.addEventListener("load", function(event) {
if(event.target.contentWindow.window.length === 0){
// 這邊就是載入失敗了 可以開始失敗處理
// do somting.....
}
})

這段最重要的就是這個

1
event.target.contentWindow.window.length

這個方法你還需要再iframe內的網站上放一個空的iframe,這樣就可以用這個方法來判斷

這是我在stackoverflow找到的解答,我覺得是滿酷的,看起來很像是一個hack方法,但其實他只是判斷iframe裡面的window對象有沒有正常而已,當他為0的時候就是iframe載入失敗了,當她為1的時候就代表iframe載入成功了

可以看一下MDN的範例就知道了 HTMLIFrameElement.contentWindow

Furk.net是一個免費的BT代抓服務網站, 由於這網站註冊需要邀請碼, 所以我將我的邀請碼直接提供出來, 有需要的人請自行取用

以下就是我這邊有的邀請碼

BZ9POE781

1MCGT4526

7M0K8AQ7R

X71ERZ3BK

1CRWKI4QR

DJ1E2NINL

S4RVJIBB8

H5W5BQXO8

IJK0C9IZL

5S08LTY6S

8PGJ89SK4

Q79YDOZNI

XZTFXBXOY

KH2M792M0

[adinserter block=”4”] [adinserter block=”9”]

2020/9/5 更新

1S0DVGD92 6KRWYOSDR RJUF8WPKU BOM9W2SOZ B7NGXKHBB L0EJ1FVWU IVI46CQ1

[adinserter block=”4”] [adinserter block=”9”]

JQRRESCL4 HVKSQ54L2 U5KPG6GL7 Q8YES5AAI 5BYKFY5YF IT4C9ACNC 75J9O9MH7

[adinserter block=”4”] [adinserter block=”9”]

furk.net填入邀請碼

註冊直接填入上圖紅色框的地方就可以

因為一些原因工作上要升級python到python3.6,不升級還沒問題,一升級問題嚴重了,升級完之後我發現我的終端機打不開,然後我就reboot,重新開機再登入之後發現整個桌面變黑了,只剩下桌面的捷徑還在,當下我有夠慌張,於是開始找辦法修復

開始嘗試解決問題

由於終端也打不開所以我直接ctrl+alt+F1進到tty1登入

ctrl+alt+F16 可以進到tty16, ctrl+alt+F7可以回到原本的gui

我當下第一個想法就是先把python3.6刪掉,因為問題是因為裝了python3.6之後才發生了

1
sudo apt-get remove python3.6

移除完之後又reboot,發現結果沒有變化,這時我想說死定了,第一次遇到這種情況,還好vscode之類的桌面捷徑還可以開啟,我就開始先備份程式碼,開始commit push到gitlab上,畢竟等下出了什麼事情,不能救回來就要做白工了

在commit的過程中我又想到既然是cinnamon掛掉的話,裝gnome能不能救回來,於是我又開始切到tty1開始裝gnome3跟gdm,裝完之後reboot, 在登入的時候選gnome桌面,發現沒有問題,可以正常進入gnome,當下有夠感動,但是又發現另一個問題,那就是gnome的終端也打不開,不過gnome的桌面跟快捷功能都是正常的

上網google了一下,有xterm這個東西,但是說真的不太習慣,而且內建的終端機不能開也是很奇怪,所以我直接用xterm打開gnome的終端直接輸入

1
gnome-terminal

發現主要問題

發現他跳了一個關於python的錯誤,大概就是寫他找不到_gi的套件,上網直接用_gi當關鍵字去找,終於找到有人跟我有類似的情況,原來就是因為python3.6少了_gi所以每次開的時候會噴這個錯誤所以就掛了,之後我照著網路上的解法終於解決了這次的問題

大致上解法

解法就是去把python3.5的_gi複製給pytohn3.6用,先進到python3 gi的資料夾

1
cd /usr/lib/python3/dist-packages/gi/

然後輸入看一下目錄下的檔案,會發現有名字很長然後gi開頭的檔案,會長的類似這個名字

1
2
_gi.cpython-35m-aarch64-linux-gnu.so
_gi_cairo.cpython-35m-aarch64-linux-gnu.so

用cp複製一份,檔名就把35m的部分改成36m

1
2
sudo cp _gi.cpython-35m-aarch64-linux-gnu.so _gi.cpython-36m-aarch64-linux-gnu.so
sudo cp _gi_cairo.cpython-35m-aarch64-linux-gnu.so _gi_cairo.cpython-36m-aarch64-linux-gnu.so

複製完之後我開啟gnome的終端機,已經是正常了,再來就是登出,登入的時候選擇cinnamon,登入也正常了,我看到正常我也是鬆了一口氣

結論

雖然說多裝了gnome但是問題解決我就覺得ok了,雖然說我覺得這應該不是最正確的解法,但至少這個方法讓我解決這次問題,在還沒裝gnome之前我還想說直接重灌mint好了,還好有多試試看其他方法

工作上因為有需求所以有自己刻類似對話框的元件,後來發現對話框的三角形部分陰影好像不太好用出來,上網找了一下發現有兩種方法可以實現對話框下方的三角形陰影,所以寫下這一篇文章防止以後忘記要怎麼做

關於三角形的實作這篇就不贅述了,可以使用三角形產生器直接做出來,這篇主要還是講解陰影的部分

三角形產生器

這邊先產生一個對話框的殼出來,position使用relative方便三角形做定位

1
2
3
4
5
6
7
.chat-block {
height: 100px;
width: 200px;
background: #d6940f;
border-radius: 8px;
position: relative;
}

然後直接用偽元素after產生出一個三角形,我這邊產生了一個向下、寬40px、高20px且顏色是橘色的三角形,用absolute定位到下方

1
2
3
4
5
6
7
8
9
10
11
12
.chat-block::after{
content: '';
width: 0;
height: 0;
border-style: solid;
border-width: 10px 10px 0 10px;
border-color: #d6940f transparent transparent;
z-index: 99;
position: absolute;
bottom: -10px;
left: 10px;
}

html的部分

1
<div class="chat-block"></div>

放上去之後應該會長得像下面的圖一樣,接下來就是開始新增邊框

對話框demo

方法一   用更大的三角形當邊框

這個方法是用一個黑色的三角形放在橘色三角形的下面,產生一個邊框的效果,但是這種邊框不能用成陰影的效果,要用成陰影的效果要用第二個方法

直接用before偽元素來產生大的黑色三角形,border-width那邊第一個參數有多1是為了上他的黑色可以緊貼對話框的黑色邊框,zindex要比局色三角形小,不然他會蓋到橘色的三角形

1
2
3
4
5
6
7
8
9
10
11
12
.chat-block::before{
content: '';
width: 0;
height: 0;
border-style: solid;
border-width: 11px 10px 0 10px;
border-color: #000 transparent transparent;
z-index: 98;
position: absolute;
bottom: -11px;
left: 10px;
}

成果大概長這樣

對話框demo 2

方法二   旋轉陰影

這個方法比較適合對話框是用陰影的情況下使用

直接把第一個方法的對話框邊框拿掉換成陰影,before偽元素的邊框顏色設為透明,一樣加上陰影

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.chat-block {
height: 100px;
width: 200px;
background: #d6940f;
border-radius: 8px;
position: relative;
z-index: 100;
box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
}

.chat-block::before{
content: '';
width: 0;
height: 0;
border-style: solid;
border-width: 10px 10px 0 10px;
border-color: transparent transparent transparent;
z-index: 98;
position: absolute;
bottom: -11px;
left: 10px;
box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
}

這個時候會發現三角形的陰影跑掉了,這個時候直接用transform轉個45度,再調整一下位置就ok了,一些相關的屬性可以再自己細細調整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.chat-block::before{
content: '';
width: 0;
height: 0;
border-style: solid;
border-width: 10px 5px 0 10px;
border-color: transparent transparent transparent;
z-index: 98;
position: absolute;
bottom: -4px;
left: 12px;
box-shadow: 3px 2px 3px rgba(0, 0, 0, 0.2);
transform: rotate(45deg);
}

大概就會像這樣 對話框demo 3

0%