摘要:第八集從零開始實現(xiàn)輸入框組件本集定位組件是交互的一大利器他與用戶的交流最為密切所以奠定了他在組件界的重要地位也算是一種如果可以的話本集也會一起說完畢竟是一個類型的一起學(xué)完收獲會很大古人云組件不封輸入框,一到面試就發(fā)慌一簡介大家如果對這個
第八集: 從零開始實現(xiàn)(輸入框input,textarea組件)
本集定位:
input組件是交互的一大利器, 他與用戶的交流最為密切, 所以奠定了他在組件界的重要地位.
textarea也算是一種input, 如果可以的話, 本集也會一起說完, 畢竟是一個類型的, 一起學(xué)完收獲會很大.
古人云:"組件不封輸入框,一到面試就發(fā)慌"
一. v-model 簡介
大家如果對 v-model這個指令的原理不熟悉, 建議去學(xué)習(xí)下vue源碼或者看看相關(guān)的分析文章, 很重要的知識, 封裝組件多了就會知道這個指令真是太棒了! 這里我就簡單說一下他的規(guī)則.
1: 父級在組件上綁定了v-model時, 其實就是在往組件里面?zhèn)鬟fvalue變量.
2: 你的組件在props上定義value, 就可以取到值.
3: 每當(dāng)組件里this.$emit("input",n)往外面發(fā)送事件的時候, 外面會把這個n值 賦值給value
4: 這么設(shè)計的原因: 你在組件里面無權(quán)改變傳入的值, 這個值你想改成什么值就要吐出去, 讓外面改.
好了說了這么多開始實戰(zhàn)吧!
二. 基本結(jié)構(gòu)
vue-cc-ui/src/components/Input/index.js
老套路, 統(tǒng)一導(dǎo)出為了適配vue.use的使用方式
import Input from "./main/input.vue" Input.install = function(Vue) { Vue.component(Input.name, Input); }; export default Input
vue-cc-ui/src/components/Input/main/input.vue
type: 這個屬性比較重要, 因為要通過它來區(qū)分input與textarea, 還可以為input指定number模式.
命名依然是bem
v-bind="$attrs" 解釋下這個的意思, $attrs指的就是用戶傳進來的屬性, 但是不包括我們組件內(nèi)部用props接收的屬性, 也不包括class style這種, 寫它是為了用戶可以傳很多input原生的屬性, 畢竟我們沒必要把所有屬性都做處理, 讓組件保有原生功能.
placeholder這種模式基本也被現(xiàn)代拋棄了, 針對他也可以封裝成一個具體的組件, 這個屬性想調(diào)整屬性實在是太困難了, 更別說我們現(xiàn)在還需要placeholder輪播,變色,點擊等等效果.
vue 在行間寫事件的時候, 事件對象會以$event的形式傳給你使用, 其實從代碼的角度來說, 是監(jiān)控到你這里用了$event關(guān)鍵詞,則把對應(yīng)的參數(shù)賦值為事件對象.
props: { value: [String, Number], placeholder: [String, Number], type: { type: String, default: "text" } },
三. 豐富事件
輸入框有很多種事件, 他們能給用戶更好的體驗性.
比如在手機端, 我們項目之前遇到的問題就是, 用戶點擊輸入框的時候, 會彈出手機鍵盤, 但是彈出的鍵盤會把輸入框頂上去, 某些型號的手機會出現(xiàn), 就算輸入完畢點擊完成, 可是輸入框還是被頂上去的狀態(tài), 后來我是借助blur 與 focus事件才兼容了這寫手機
很多輸入框也采取節(jié)流與防抖, 比如做搜索的相關(guān)模糊匹配
有些以搜索為主的頁面, 需要自動聚焦
四. 各種狀態(tài)
禁用狀態(tài), 置灰并且把鼠標(biāo)變?yōu)榻範(fàn)顟B(tài) (disabled)
只讀, 并不置灰, 但是也不能改 (readonly)
具體樣式會在后面出來詳細解釋
五. 為輸入框添加狀態(tài), 并附上icon選項
很多輸入框左右都要放個icon充充門面, 分為左側(cè)與右側(cè)icon
右側(cè)icon允許輸入文字, icon要有相應(yīng)的點擊效果
當(dāng)組件為disabled狀態(tài)的時候, icon也要相應(yīng)的置灰
效果圖
六. 清空按鈕
現(xiàn)在的輸入框基本都有這個清空按鈕, 畢竟可以節(jié)省用的時間, 也算是個好功能,
當(dāng)用戶傳入clear的時候會判斷, 是否禁止修改, 框內(nèi)是否有值, 是否是hover狀態(tài)
hover事件放在父級上
清除事件, 對外返回空就ok
clickClear() { this.$emit("input", ""); this.$emit("change", ""); },判斷是否顯示
computed: { showClear() { if ( this.clear && // 開啟功能 !this.disabled && // 不是禁用 !this.readonly && // 不是只讀 this.value!== "" && // 不是空值 (this.hovering || this.focus) // 聚焦或者hover狀態(tài)下 )return true; return false; } },vue-cc-ui/src/style/Input.scss
// 引入老四樣 @import "./common/var.scss"; @import "./common/extend.scss"; @import "./common/mixin.scss"; @import "./config/index.scss"; // 這里畢竟是兩個月前寫的組件, 命名方面不是很好, 接下來會統(tǒng)一改正 @include b(input) { cursor: pointer; position: relative; align-items: center; display: inline-flex; // 直接flex會獨占一行 background-color: white; transition: all .3s; @include b(input__inner) { border: none; flex: 1; width: 100%; font-size: 1em; padding: 9px 16px; &:focus { outline: 0; } // 這樣寫對障礙閱讀不是很友好 @include placeholder{ // placeholder設(shè)置顏色很頭疼, 請看下面 color: $--color-input-placeholder; } }; @include b(input__prefix) { align-items: center; display: inline-flex; &:hover{transform: scale(1.1)} @include when(left) { padding-left:6px; } @include when(right) { padding-right:6px; } }; @include b(input__clear){ position: absolute; right: 24px; &:hover{ animation: size .5s infinite linear;} }; @include b(input--input__disabled){ @include commonShadow(disabled); }; @at-root { @include b(input__normal){ @include commonShadow($--color-black); &:hover { z-index: 6; transform: scale(1.2); } } @include b(input__error){ @include commonShadow(danger); } @include b(input__abnormal){ @include commonShadow($--color-black); } } }element 這個處理做的也不錯
@mixin placeholder { &::-webkit-input-placeholder { @content; } &::-moz-placeholder { @content; } &:-ms-input-placeholder { @content; } }七. textarea 文本域
基本結(jié)構(gòu)
在用戶type輸入的是textarea時候開啟
把上面的基礎(chǔ)功能復(fù)制下來, 直接放上就可以用的
textareaCalcStyle: 來設(shè)置他的寬高, 畢竟他與input不同, 可能需要很大面積
用戶可以設(shè)置最大高度與最小高度
難點: 如果用戶選擇了自動適應(yīng)高度那就麻煩了, 這個組件沒有提供原生的解決方案, 第一版我是采用獲取其高度進行運算得出來的, 但是及特殊的情況會有bug, 最后參考了element-ui的實現(xiàn)方式, 這里也讓我學(xué)習(xí)到了.
針對textarea獲取其真實高度進行高度的動態(tài)賦值;
我來說說他的原理, 制作一個與textarea對象相同的元素, 獲取他的滾動距離與高度, 計算出總的高度, 然后賦值給真正的textarea, 這里的亮點就是怎么做一個相同的dom, 因為用戶可能給這個dom不同的樣式, 不同的class, 各種各樣的父級, 腹肌還會影響這個元素的樣式;// 個人建議, 這種生命周期函數(shù)都放在最底部, 并且要保持單一職責(zé) mounted() { this.$nextTick(this.resizeTextarea); }1: 判斷是不是 autosize自動高度, 并且是組件autosize
2: 用戶是否設(shè)置了最大高度與最小高度的限制
3: 這個函數(shù)只負責(zé)處理是否進行計算 calcTextareaHeight 負責(zé)計算.resizeTextarea() { const { autosize, type } = this; if (type !== "autosize" || !autosize) return; const minRows = autosize.min; const maxRows = autosize.max; this.textareaCalcStyle = this.calcTextareaHeight( this.$refs.textarea, minRows, maxRows ); },calcTextareaHeight
calcTextareaHeight(el, min, max) { // 也算是單例模式, 制作一個元素就行了 if (!window.hiddenTextarea) { window.hiddenTextarea = document.createElement("textarea"); document.body.appendChild(window.hiddenTextarea); } // 取得他的屬性, 具體獲取屬性函數(shù)下面會講 let [boxSizing, paddingSize, borderSize] = this.calculateNodeStyling(el); // 滾動距離 let height = window.hiddenTextarea.scrollHeight; // 是否是怪異盒模型, 進行分別的計算 if (boxSizing === "border-box") { height = height + borderSize; } else { height = height - paddingSize; } // 及時清理,讓用戶看不到這個元素 window.hiddenTextarea.parentNode && window.hiddenTextarea.parentNode.removeChild(window.hiddenTextarea); window.hiddenTextarea = null; if (min && height < min) height = min; else if (max && height > max) height = max; return { height: height + "px" }; }calculateNodeStyling
calculateNodeStyling(el) { // 模擬元素通過值的輸入模擬真正的元素 window.hiddenTextarea.value = this.value; const style = window.getComputedStyle(el); const boxSizing = style.getPropertyValue("box-sizing"); const paddingTop = style.getPropertyValue("padding-top"); const paddingBottom = style.getPropertyValue("padding-bottom"); const borderTopWidth = style.getPropertyValue("border-top-width"); const borderBottomWidth = style.getPropertyValue("border-bottom-width"); const contextStyle = this.CONTEXT_STYLE.map( name => `${name}:${style.getPropertyValue(name)}` ).join(";"); window.hiddenTextarea.setAttribute( "style", `${contextStyle};${this.HIDDEN_STYLE}` ); return [ boxSizing, parseInt(paddingBottom) + parseInt(paddingTop), parseInt(borderBottomWidth) + parseInt(borderTopWidth) ]; },上面 用到的this.CONTEXT_STYLE數(shù)據(jù)是樣式的列表
data() { return { focus: false, // 監(jiān)聽輸入框的聚焦失焦 hovering: false, textareaCalcStyle: {}, CONTEXT_STYLE: [ "width", "font-size", "box-sizing", "line-height", "padding-top", "font-family", "font-weight", "text-indent", "border-width", "padding-left", "padding-right", "letter-spacing", "padding-bottom", "text-rendering", "text-transform" ] }; },至此才把這個組件做完, 好辛苦
end
如果想做到面面俱到就沒有簡單的組件, element上的每個組件都值得借鑒.
其實很多原理明白之后學(xué)習(xí)才能更快捷, 最近拿出時間與大家風(fēng)向一下vue的實現(xiàn)原理, vue-router vuex等等的實現(xiàn)原理, 希望能對大家對我自己都有幫助吧,, 只能說學(xué)海無涯回頭是岸文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/106365.html
摘要:第八集從零開始實現(xiàn)輸入框組件本集定位組件是交互的一大利器他與用戶的交流最為密切所以奠定了他在組件界的重要地位也算是一種如果可以的話本集也會一起說完畢竟是一個類型的一起學(xué)完收獲會很大古人云組件不封輸入框,一到面試就發(fā)慌一簡介大家如果對這個 第八集: 從零開始實現(xiàn)(輸入框input,textarea組件) 本集定位: input組件是交互的一大利器, 他與用戶的交流最為密切, 所以奠...
摘要:第十集從零開始實現(xiàn)計數(shù)器組件本集定位聽到計數(shù)器這個名字很多人是不是一瞬間沒有什么印象畢竟這個組件用的比較少就是那種左邊一個右邊一個控制某些數(shù)量的時候才會用到比如我之前做的商城小程序只有下單頁面的規(guī)格彈出框里面才有他的身影如果是涉及到處理商 第十集: 從零開始實現(xiàn)( 計數(shù)器組件 ) 本集定位: 聽到計數(shù)器這個名字很多人是不是一瞬間沒有什么印象, 畢竟這個組件用的比較少,就是那種左邊...
摘要:第十集從零開始實現(xiàn)計數(shù)器組件本集定位聽到計數(shù)器這個名字很多人是不是一瞬間沒有什么印象畢竟這個組件用的比較少就是那種左邊一個右邊一個控制某些數(shù)量的時候才會用到比如我之前做的商城小程序只有下單頁面的規(guī)格彈出框里面才有他的身影如果是涉及到處理商 第十集: 從零開始實現(xiàn)( 計數(shù)器組件 ) 本集定位: 聽到計數(shù)器這個名字很多人是不是一瞬間沒有什么印象, 畢竟這個組件用的比較少,就是那種左邊...
摘要:第十一集從零開始實現(xiàn)切換組件本集定位我們先來聊聊切換的意義不管是手機還是屏幕的大小是有限的人眼睛看到的范圍也是有限的人們看信息的時候并不喜歡跳轉(zhuǎn)這種操作或是我們要查某個知識點進入網(wǎng)站之后看了幾眼沒有需要的相關(guān)信息也就理所當(dāng)然的退出去繼續(xù)搜索 第十一集: 從零開始實現(xiàn)( tab切換組件 ) 本集定位: 我們先來聊聊 tab 切換的意義, 不管是手機還是pc, 屏幕的大小是有限的,...
摘要:第一集從零開始實現(xiàn)環(huán)境的搭建工程定位本套工程定位在端針對的組件庫名字的由來是我從年養(yǎng)到現(xiàn)在的一直大金毛是我的吉祥物原因本人上一份工作參與了大型的保險公司后臺管理系統(tǒng)的搭建對的端框架有過一定的了解感受到了他們真的很強大同時也存在少許的不足其實 第一集: 從零開始實現(xiàn)(環(huán)境的搭建) 工程定位: 本套工程, 定位在pc端針對vue的ui組件庫 名字的由來 cc是我從2015年養(yǎng)到現(xiàn)在的...
閱讀 3550·2021-10-09 09:43
閱讀 6148·2021-09-07 10:15
閱讀 2746·2019-08-30 14:03
閱讀 3073·2019-08-29 11:01
閱讀 1715·2019-08-29 10:56
閱讀 1074·2019-08-28 17:52
閱讀 3501·2019-08-26 11:42
閱讀 2547·2019-08-26 10:33