• element文本域选择框_Element分析(组件篇)——Input


    input组件相对来说复杂一点,我们先从它用到的一个工具库calcTextareaHeight.js进行分析。

    calcTextareaHeight.js

    calcTextareaHeight.js使用来计算文本框的高度的,我们根据代码顺序从上往下进行分析。

    HIDDEN_STYLE

    HIDDEN_STYLE是一个常量,存储隐藏时候的css样式的。

    const HIDDEN_STYLE = `

    height:0 !important;

    visibility:hidden !important;

    overflow:hidden !important;

    position:absolute !important;

    z-index:-1000 !important;

    top:0 !important;

    right:0 !important

    `;

    CONTEXT_STYLE

    CONTEXT_STYLE也是一个常量,用来存储要查询的样式名。

    const CONTEXT_STYLE = [

    'letter-spacing',

    'line-height',

    'padding-top',

    'padding-bottom',

    'font-family',

    'font-weight',

    'font-size',

    'text-rendering',

    'text-transform',

    'width',

    'text-indent',

    'padding-left',

    'padding-right',

    'border-width',

    'box-sizing'

    ];

    calculateNodeStyling

    calculateNodeStyling用来获取结点的某些样式。

    function calculateNodeStyling(node) {undefined

    const style = window.getComputedStyle(node); // 获取结点的计算后的样式,即实际渲染的样式

    const boxSizing = style.getPropertyValue('box-sizing'); // 获取 box-sizing 的值

    // 上下的 padding 之和

    const paddingSize = (

    parseFloat(style.getPropertyValue('padding-bottom')) +

    parseFloat(style.getPropertyValue('padding-top'))

    );

    // 上下的边框宽度和(其实是看上去的高度)

    const borderSize = (

    parseFloat(style.getPropertyValue('border-bottom-width')) +

    parseFloat(style.getPropertyValue('border-top-width'))

    );

    // 其他一些样式

    const contextStyle = CONTEXT_STYLE

    .map(name => `${name}:${style.getPropertyValue(name)}`)

    .join(';');

    return { contextStyle, paddingSize, borderSize, boxSizing };

    }

    calcTextareaHeight

    calcTextareaHeight是最终暴露出去的函数,用来计算文本域的高度。

    export default function calcTextareaHeight(

    targetNode, // 要计算的结点

    minRows = null, // 最小的行数

    maxRows = null // 最大的行数

    ) {undefined

    if (!hiddenTextarea) { // 来创建一个隐藏的文本域,所有的计算都是在这上面进行的

    hiddenTextarea = document.createElement('textarea');

    document.body.appendChild(hiddenTextarea);

    }

    // 获取结点一些样式值

    let {undefined

    paddingSize,

    borderSize,

    boxSizing,

    contextStyle

    } = calculateNodeStyling(targetNode);

    // 设置相应的样式

    hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);

    // 设置内容,按优先级一次是 结点的 value, 结点的 placeholder, 以及空字符串

    hiddenTextarea.value = targetNode.value || targetNode.placeholder || '';

    // 获取滚动高度

    let height = hiddenTextarea.scrollHeight;

    if (boxSizing === 'border-box') {undefined

    // 如果是 border-box,说明高度得加上边框

    height = height + borderSize;

    } else if (boxSizing === 'content-box') {undefined

    // 如果是 content-box,说明得减去上下内边距

    height = height - paddingSize;

    }

    // 计算单行高度,先清空内容

    hiddenTextarea.value = '';

    // 再用滚动高度减去上下内边距

    let singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;

    if (minRows !== null) { // 如果参数传递了 minRows

    let minHeight = singleRowHeight * minRows; // 说明最少应当有这么多行的高度

    if (boxSizing === 'border-box') { // 如果是 border-box,还得加上上下内边距和上下边框的宽度

    minHeight = minHeight + paddingSize + borderSize;

    }

    height = Math.max(minHeight, height); // 取二者最大值

    }

    if (maxRows !== null) { // 如果参数传递了 maxRows

    let maxHeight = singleRowHeight * maxRows; // 说明最多只能有这么多行的高度

    if (boxSizing === 'border-box') { // 如果是 border-box,还得加上上下内边距和上下边框的宽度

    maxHeight = maxHeight + paddingSize + borderSize;

    }

    height = Math.min(maxHeight, height); // 取二者最小值

    }

    // 返回文本域应当设置的高度

    return { height: height + 'px'};

    };

    input.vue

    input组件较为繁琐,我们一点点分析。

    生命周期

    created

    创建的时候会监听inputSelect事件,并调用inputSelect方法。

    created() {undefined

    this.$on('inputSelect', this.inputSelect);

    },

    inputSelect方法会调用refs上的input的原生的select方法,来选中该input。

    methods: {undefined

    inputSelect() {undefined

    this.$refs.input.select();

    },

    }

    mounted

    挂载的时候,会调用resizeTextarea方法来设置文本域的大小。

    mounted() {undefined

    this.resizeTextarea();

    }

    methods: {undefined

    resizeTextarea() {undefined

    if (this.$isServer) return; // 如果是服务端渲染,直接返回,不进行下面的逻辑

    var { autosize, type } = this;

    if (!autosize || type !== 'textarea') return; // 如果 autosize 是 false,或者当前不是文本域,也直接返回

    const minRows = autosize.minRows; // 最少行数

    const maxRows = autosize.maxRows; // 最大行数

    this.textareaStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows); // 计算文本域的高度,并赋值

    },

    }

    最外层

    最外层是一个div,上面设置了一些动态的class。

    type

    type是一个prop,它默认设置为text,如果设置为textarea,表明当前是一个文本域。

    props: {undefined

    type: {undefined

    type: String,

    default: 'text'

    },

    }

    size

    size也是一个prop,用来设置输入框的大小,在textarea下无效。

    props: {undefined

    size: String,

    }

    disabled

    disabled也是一个prop,用来设置是否可用。

    props: {undefined

    disabled: Boolean,

    }

    prepend、append

    这两个都是在设置输入框组的时候使用的,通过具名slot传入,分别放置于input的首和尾。

    input

    然后,根据type的不同使用v-if分别渲染input或者textarea,我们先分析input部分。

    前置元素

    前置元素直接通过具名slot传入。

    input 图标

    图标也是通过具名slot传入的,也可以通过prop中的icon传入图标名。

    class="el-input__icon"

    :class="'el-icon-' + icon"

    v-if="icon"

    @click="handleIconClick">

    上面还绑定了一个handleIconClick的点击事件,它会触发click事件:

    methods: {undefined

    handleIconClick(event) {undefined

    this.$emit('click', event);

    },

    }

    input

    然后是最重要的input部分,上面大部分是prop,不进行讲解,其余的我们将一一讲解。

    v-if="type !== 'textarea'"

    class="el-input__inner"

    :type="type" // 类型

    :name="name" // 名字

    :placeholder="placeholder" // 默认值

    :disabled="disabled" // 是否禁用

    :readonly="readonly" // 是否只读

    :maxlength="maxlength" // 输入的最大长度

    :minlength="minlength" // 输入的最小长度(暂时不支持)

    :autocomplete="autoComplete" // 自动补全

    :autofocus="autofocus" // 自动聚焦

    :min="min" // 允许输入的最小值(数字或者日期)

    :max="max" // 允许输入的最大值(数字或者日期)

    :form="form" // 绑定的表单(不是原生的)

    :value="currentValue" // 输入值

    ref="input" // 引用

    @input="handleInput" // 输入事件

    @focus="handleFocus" // 获得焦点事件

    @blur="handleBlur" // 失去焦点事件

    >

    value

    value改变的时候会调用setCurrentValue。

    watch: {undefined

    'value'(val, oldValue) {undefined

    this.setCurrentValue(val);

    }

    },

    而setCurrentValue是用来改变当前值的。

    methods: {undefined

    setCurrentValue(value) {undefined

    if (value === this.currentValue) return; // 如果新旧值一致直接返回

    this.$nextTick(_ => {undefined

    this.resizeTextarea(); // 下一个DOM更新周期时,重新设置文本域大小

    });

    this.currentValue = value; // 改变当前值

    this.$emit('input', value); // 触发 input 事件

    this.$emit('change', value); // 触发 change 事件

    this.dispatch('ElFormItem', 'el.form.change', [value]); // 向父级的派发 el.form.change 事件

    }

    }

    handleInput

    处理输入事件。

    methods: {undefined

    handleInput(event) {undefined

    this.setCurrentValue(event.target.value); // 改变当前值

    },

    }

    handleFocus

    handleFocus用来处理获得焦点的事件,会直接触发focus事件。

    methods: {undefined

    handleFocus(event) {undefined

    this.$emit('focus', event);

    },

    }

    handleBlur

    handleBlur用来处理失去焦点的事件。

    methods: {undefined

    handleBlur(event) {undefined

    this.$emit('blur', event); // 触发 blur 事件

    this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]); // 向父组件派发 el.form.blur 事件

    },

    }

    loading

    loading会根据计算属性validating来决定是否渲染。

    computed: {undefined

    validating() {undefined

    return this.$parent.validateState === 'validating';

    }

    },

    后置元素

    后置元素只能根据具名slot传入。

    Textarea

    如果type设置为textarea则会渲染textarea,上面绑定的都和input类似,不再多说,多了一个textareaStyle,是根据calcTextareaHeight计算出来的。

    v-else

    class="el-textarea__inner"

    :value="currentValue"

    @input="handleInput"

    ref="textarea"

    :name="name"

    :placeholder="placeholder"

    :disabled="disabled"

    :style="textareaStyle"

    :readonly="readonly"

    :rows="rows"

    :form="form"

    :autofocus="autofocus"

    :maxlength="maxlength"

    :minlength="minlength"

    @focus="handleFocus"

    @blur="handleBlur">
    ————————————————
    版权声明:本文为CSDN博主「weixin_39533896」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_39533896/article/details/111516689

  • 相关阅读:
    有道
    excel 数据入库
    iso-8859-1 Unicode 编码
    爬虫编码问题
    WIKi 百科爬虫
    降低耦合性获取微博数据
    Python基础总结3-字符串
    Python基础总结2
    Linux常用命令04(其他命令)
    Linux常用命令03(系统信息)
  • 原文地址:https://www.cnblogs.com/wsj1/p/16032509.html
Copyright © 2020-2023  润新知