element-ui inputNumber組件源碼分析整理筆記(三)

来源:https://www.cnblogs.com/fangnianqin/archive/2018/11/29/10038047.html
-Advertisement-
Play Games

inputNumber算是一個比較簡單的組件了。 解析: (1)先看下html結構 左邊的減號和右邊的加號是通過絕對定位,設置在input左右的padding位置的,input的css代碼如下: 這個inputNumber源碼還算簡單,多看幾遍就懂了 ...


inputNumber組件

<template>
    <[email protected]禁止input中數字的拖動-->
  <div
    @dragstart.prevent
    :class="[
      'el-input-number',
      inputNumberSize ? 'el-input-number--' + inputNumberSize : '',
      { 'is-disabled': inputNumberDisabled },
      { 'is-without-controls': !controls },
      { 'is-controls-right': controlsAtRight }
    ]">
    <span
      class="el-input-number__decrease"
      role="button"
      v-if="controls"
      v-repeat-click="decrease"
      :class="{'is-disabled': minDisabled}"
      @keydown.enter="decrease">
      <i :class="`el-icon-${controlsAtRight ? 'arrow-down' : 'minus'}`"></i>
    </span>
    <span
      class="el-input-number__increase"
      role="button"
      v-if="controls"
      v-repeat-click="increase"
      :class="{'is-disabled': maxDisabled}"
      @keydown.enter="increase">
      <i :class="`el-icon-${controlsAtRight ? 'arrow-up' : 'plus'}`"></i>
    </span>
    <el-input
      ref="input"
      :value="currentInputValue"
      :placeholder="placeholder"
      :disabled="inputNumberDisabled"
      :size="inputNumberSize"
      :max="max"
      :min="min"
      :name="name"
      :label="label"
      @keydown.up.native.prevent="increase"
      @keydown.down.native.prevent="decrease"
      @blur="handleBlur"
      @focus="handleFocus"
      @change="handleInputChange">
    </el-input>
  </div>
</template>
<script>
  import ElInput from 'element-ui/packages/input';
  import Focus from 'element-ui/src/mixins/focus';
  //RepeatClick,用來控制左鍵按下時不斷觸發事件
  import RepeatClick from 'element-ui/src/directives/repeat-click';

  export default {
    name: 'ElInputNumber',
    mixins: [Focus('input')],
    inject: {
      elForm: {
        default: ''
      },
      elFormItem: {
        default: ''
      }
    },
    directives: {
      repeatClick: RepeatClick
    },
    components: {
      ElInput
    },
    props: {
      step: { //計數器步長
        type: Number,
        default: 1
      },
      max: { //設置計數器允許的最大值
        type: Number,
        default: Infinity
      },
      min: { //設置計數器允許的最小值
        type: Number,
        default: -Infinity
      },
      value: {}, //綁定值
      disabled: Boolean, //是否禁用計數器
      size: String, //計數器尺寸
      controls: { //是否使用控制按鈕
        type: Boolean,
        default: true
      },
      controlsPosition: { //控制按鈕位置
        type: String,
        default: ''
      },
      name: String, //原生屬性
      label: String, //輸入框關聯的label文字
      placeholder: String, //輸入框預設 placeholder
      precision: { //數值精度
        type: Number,
        validator(val) {
          return val >= 0 && val === parseInt(val, 10);
        }
      }
    },
    data() {
      return {
        currentValue: 0
      };
    },
    watch: {
      value: {
        //確認是否以當前的初始值執行handler的函數。
        immediate: true,
        handler(value) {
          //Number() 函數把對象的值轉換為數字。
          let newVal = value === undefined ? value : Number(value);
          if (newVal !== undefined) {
            if (isNaN(newVal)) {
              return;
            }
            if (this.precision !== undefined) {
              //如果數值精度存在,將數字按精度轉換
              newVal = this.toPrecision(newVal, this.precision);
            }
          }
          if (newVal >= this.max) newVal = this.max;
          if (newVal <= this.min) newVal = this.min;
          this.currentValue = newVal;
          this.$emit('input', newVal);
        }
      }
    },
    computed: {
      // 返回當前減號是否被禁用
      minDisabled() {
        // 當前值-計數器步長<最小值時,減號被禁用,不能再繼續減
        return this._decrease(this.value, this.step) < this.min;
      },
      maxDisabled() {
        return this._increase(this.value, this.step) > this.max;
      },
      //返回數值的精度
      numPrecision() {
         // precision 的值必須是一個非負整數,並且不能小於 step 的小數位數。
        const { value, step, getPrecision, precision } = this;
        const stepPrecision = getPrecision(step);
        if (precision !== undefined) {
          //如果step 的小數位數大於數值精度時,控制台輸出警告並返回數值精度
          if (stepPrecision > precision) {
            console.warn('[Element Warn][InputNumber]precision should not be less than the decimal places of step');
          }
          return precision;
        } else {
            //如果step 的小數位數小於數值精度時,再比較數值的精度和step的精度,取最大值
          return Math.max(getPrecision(value), stepPrecision);
        }
      },
      // 控制按鈕的位置
      controlsAtRight() {
        //  當控制按鈕存在,並且控制按鈕的位置為right時,此處通過添加is-controls-right類來改變控制按鈕的位置,使控制按鈕在右邊顯示。
        return this.controls && this.controlsPosition === 'right';
      },
      _elFormItemSize() {
        return (this.elFormItem || {}).elFormItemSize;
      },
      //計數器的大小
      inputNumberSize() {
        return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
      },
      // 是否禁用計數器
      inputNumberDisabled() {
        return this.disabled || (this.elForm || {}).disabled;
      },
      currentInputValue() {
        const currentValue = this.currentValue;
        if (typeof currentValue === 'number' && this.precision !== undefined) {
          return currentValue.toFixed(this.precision);
        } else {
          return currentValue;
        }
      }
    },
    methods: {
      //按精度轉換數值
      toPrecision(num, precision) {
        if (precision === undefined) precision = this.numPrecision;
         //toFixed() 方法可把 Number 四捨五入為指定小數位數的數字,返回字元串;parseFloat()函數可解析一個字元串,並返回一個浮點數。
        return parseFloat(parseFloat(Number(num).toFixed(precision)));
      },
      //獲取value的小數位數
      getPrecision(value) {
        if (value === undefined) return 0;
        const valueString = value.toString();
        const dotPosition = valueString.indexOf('.');
        let precision = 0;
        if (dotPosition !== -1) {
          //valueString.length減去小數點前面的位數,剩下的就是小數點後面的位數
          precision = valueString.length - dotPosition - 1;
        }
        return precision;
      },
      _increase(val, step) {
        if (typeof val !== 'number' && val !== undefined) return this.currentValue;
        const precisionFactor = Math.pow(10, this.numPrecision);
        return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor);
      },
      //返回value減去step後的值
      _decrease(val, step) {
        if (typeof val !== 'number' && val !== undefined) return this.currentValue;
        //Math.pow()計算10的this.numPrecision次方
        const precisionFactor = Math.pow(10, this.numPrecision);
        //這裡主要是為了減少誤差
        return this.toPrecision((precisionFactor * val - precisionFactor * step) / precisionFactor);
      },
      increase() {
        if (this.inputNumberDisabled || this.maxDisabled) return;
        const value = this.value || 0;
        const newVal = this._increase(value, this.step);
        this.setCurrentValue(newVal);
      },
       //點擊減號時觸發的事件
      decrease() {
        if (this.inputNumberDisabled || this.minDisabled) return;
        const value = this.value || 0;
        const newVal = this._decrease(value, this.step);
        this.setCurrentValue(newVal);
      },
      handleBlur(event) {
        this.$emit('blur', event);
        this.$refs.input.setCurrentValue(this.currentInputValue);
      },
      handleFocus(event) {
        this.$emit('focus', event);
      },
      setCurrentValue(newVal) {
        const oldVal = this.currentValue;
        if (typeof newVal === 'number' && this.precision !== undefined) {
          newVal = this.toPrecision(newVal, this.precision);
        }
        if (newVal >= this.max) newVal = this.max;
        if (newVal <= this.min) newVal = this.min;
        if (oldVal === newVal) {
          //改變input的當前值
          this.$refs.input.setCurrentValue(this.currentInputValue);
          return;
        }
        this.$emit('input', newVal);
        this.$emit('change', newVal, oldVal);
        this.currentValue = newVal;
      },
      handleInputChange(value) {
        const newVal = value === '' ? undefined : Number(value);
        if (!isNaN(newVal) || value === '') {
          this.setCurrentValue(newVal);
        }
      },
      select() {
        this.$refs.input.select();
      }
    },
    mounted() {
      let innerInput = this.$refs.input.$refs.input;
      innerInput.setAttribute('role', 'spinbutton');
      innerInput.setAttribute('aria-valuemax', this.max);
      innerInput.setAttribute('aria-valuemin', this.min);
      innerInput.setAttribute('aria-valuenow', this.currentValue);
      innerInput.setAttribute('aria-disabled', this.inputNumberDisabled);
    },
    updated() {
      if (!this.$refs || !this.$refs.input) return;
      const innerInput = this.$refs.input.$refs.input;
      innerInput.setAttribute('aria-valuenow', this.currentValue);
    }
  };
</script>

解析:
(1)先看下html結構

 <div class="el-input-number">
        <!--左邊的減號-->
       <span class="el-input-number__decrease">
           <i class="el-icon-minus"></i>
       </span>
        <!--右邊的加號-->
       <span class="el-input-number__increase">
          <i class="el-icon-plus"></i>
       </span>
        <!--中間的輸入框-->
       <el-input ref="input"></el-input>
</div>


左邊的減號和右邊的加號是通過絕對定位,設置在input左右的padding位置的,input的css代碼如下:

.el-input-number .el-input__inner {
    -webkit-appearance: none;
    padding-left: 50px;
    padding-right: 50px;
    text-align: center;
}

這個inputNumber源碼還算簡單,多看幾遍就懂了

Card 組件

<template>
  <div class="el-card" :class="shadow ? 'is-' + shadow + '-shadow' : 'is-always-shadow'">
      <!--頭部:設置 header,也可以通過 slot#header 傳入 DOM-->
    <div class="el-card__header" v-if="$slots.header || header">
      <slot name="header">{{ header }}</slot>
    </div>
      <!--內容部分-->
    <div class="el-card__body" :style="bodyStyle">
      <slot></slot>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'ElCard',
    props: {
      header: {}, //設置 header,也可以通過 slot#header 傳入DOM
      bodyStyle: {}, //設置 body 的樣式
      shadow: {  //設置陰影顯示時機
        type: String
      }
    }
  };
</script>
<template>
  <span class="el-breadcrumb__item">
    <span
      :class="['el-breadcrumb__inner', to ? 'is-link' : '']"
      ref="link"
      role="link">
      <!--插入文字-->
      <slot></slot>
    </span>
      <!--圖標分隔符-->
    <i v-if="separatorClass" class="el-breadcrumb__separator" :class="separatorClass"></i>
      <!--分隔符-->
    <span v-else class="el-breadcrumb__separator" role="presentation">{{separator}}</span>
  </span>
</template>
<script>
  export default {
    name: 'ElBreadcrumbItem',
    props: {
      to: {}, //路由跳轉對象,同 vue-router 的 to
      replace: Boolean //在使用 to 進行路由跳轉時,啟用 replace 將不會向 history 添加新記錄
    },
    data() {
      return {
        separator: '',
        separatorClass: ''
      };
    },

    inject: ['elBreadcrumb'],

    mounted() {
      //獲取父組件的separator
      this.separator = this.elBreadcrumb.separator;
      //獲取父組件的separatorClass
      this.separatorClass = this.elBreadcrumb.separatorClass;
      const link = this.$refs.link;
      link.setAttribute('role', 'link');
      //添加點擊事件
      link.addEventListener('click', _ => {
        const { to, $router } = this;
        if (!to || !$router) return;
        //根據replace的值確定是replace還是push,replace 將不會向 history 添加新記錄
        this.replace ? $router.replace(to) : $router.push(to);
      });
    }
  };
</script>

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在掘金上看到了一位大佬發了一篇很詳細的面試記錄文章 "《一年半經驗,百度、有贊、阿裡面試總結》" ,為了查漏補缺,抽空就詳細做了下。( 估計只有我這麼無聊了哈哈哈 ) 有給出的或者有些不完善的答案,也儘力給出/完善了(可能有錯,大家自行辨別)。有些很困難的題目(例如實現 ),附帶相關鏈接(懶癌患者福 ...
  • 1. Virtual DOM是什麼 Virtual DOM,即虛擬DOM樹。瀏覽器在解析文件時,會將 文檔轉換為 對象,在瀏覽器環境中運行的腳本文件都可以獲取到它,通過操作 對象暴露的介面可以直接操作頁面上的DOM節點。但是DOM讀寫是非常耗性能的,很容易觸發不必要的重繪和重排,為了更好地處理DOM ...
  • 一、DOM對象 DOM對象整體包括: HTML DOM Document對象 HTML DOM 元素對象 HTML DOM 屬性對象 HTML DOM 事件對象 HTML DOM Console 對象 CSS Style Declaration 對象 二、 Document對象詳解 HTML DOM ...
  • 棧是一種LIFO(Last-In-First-Out,後進先出)的數據結構著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。原文: https://www.w3cplus.com/javascript/array-part-3.html © w3cplus.com 棧是一種後進先出 ...
  • 接上一篇,這裡使用 sequelize 來連接 postgresql 資料庫 1、安裝 sequelize,資料庫驅動 pg 2、新建配置文件夾 conf 及 配置文件 db.conf.ts 3、連接資料庫,新建文件夾 db 及 配置文件 db.ts 4、資料庫實體類,新建文件夾 models 及文 ...
  • 函數: 函數在調用的時候,會形成一個私有作用域,內部的變數不會被外面訪問,這種保護機制叫閉包。這就意味著函數調用完畢,這個函數形成的棧記憶體會被銷毀。 但有時候我們不希望他被銷毀。 函數歸屬誰跟它在哪調用沒有關係,跟在哪定義有關。 Fn()調用完畢後得到的是一個匿名函數,但是這個函數在fn這個作用域下 ...
  • 一、js判斷數組是否為空 方法一: arr.length 二、js判斷數組是否含有某個值 方法一: arr.indexOf() 方法二: for迴圈結合if判斷 方法三: arr.find(callback) ...
  • 1.解構賦值可以輕鬆獲取對象或者數組中的數據 結果: json中的數據就被輕鬆獲取; 2.解構複製可以交換變數 結果: a=4,b=3,c=2,d=1 賦值的過程需要保證兩邊的數據格式匹配 [a,b,c,d]=[d,c,b,]; d的值將為underfinded 3.對象的解構賦值 結果,666,8 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...