Эссе по построению фреймворка проекта --- написание входных компонентов

внешний интерфейс Ресурсы изображений Icon регулярное выражение

Продолжая предыдущую статью, фреймворк проекта, который упорно трудился несколько дней, наконец-то доступен. Вы можете начать писать страницы прямо сейчас?

Раз босс сказал, давайте сами напишем UI-фреймворк, значит, сами напишем.


Хотя приятно сказать да. Когда приходит время писать, я не знаю, с чего начать.

Тогда мы будем приходить понемногу. Начните с фреймворка компонентов и сделайте это понемногу.


Во-первых, организуйте каталог фреймворка пользовательского интерфейса. После долгого разговора с моим боссом я, наконец, решил использовать эту структуру каталогов:


Красные стрелки показывают, где бизнес-компоненты содержат компоненты бизнес-класса в проекте. Например, головная навигация, личная информационная карта и т. д.

Зеленые стрелки показывают, где компоненты фреймворка содержат базовые компоненты фреймворка в проекте. Например, кнопки, поля ввода, переключатели и т. д.

Синяя стрелка — это файл экспорта. Унифицированный экспорт всех компонентов для легкого вызова (будет рассмотрено далее в статье)


хорошо, давайте начнем с ввода


Написание компонента ввода

Давайте сначала посмотрим на визуализацию:


Примерно так. Пользовательский интерфейс очень простой, а функций достаточно. (Здесь я высоко оцениваю работу Brother UI)

Я разделил его вот так (на фото) Каждая цветная коробка отличаетсяслот (именованный слот)


Примерно такой код:

<template>
  <div class="input-wrapper">
    <div class="input-content">
      <div class="input__left">
        <slot name="left"></slot> //红色框插槽
      </div>
      <div class="input__center">
        <input type="text" title="">
        <div class="input__center__tools">
          <i class="iconfont icon-qingchu" v-show="inputValue" @click="clearInputValue"></i> 
         //清除value的地方
        </div>
      </div>
      <div class="input__right">
        <slot name="right"></slot> //input右侧的自定义区。可以放置“获取验证码”之类的操作
      </div>
    </div>
    <div class="input-tip">
      <slot name="tip"></slot> //下方提示区域插槽
    </div>
  </div>
</template>

css использует гибкую верстку. Размер шрифта / значка, расстояние между элементами использует макет rem, именование классов использует метод bem.

CSS:

<style scoped>
  .input__left .iconfont {
    font-size: 2rem;
  }

  .input-content {
    display: flex;
    flex-direction: row;
  }

  .input__left {
    padding-bottom: 0.4rem;
  }

  .input__left > span {
    font-size: 1.5rem;
  }

  .input__center {
    margin-left: .5rem;
    flex: 1;
    display: flex;
    flex-direction: row;
    padding-bottom: .3rem;
    border-bottom: 1px solid #E9E9E9;
  }

  .input__center > .input__center__tools > .iconfont {
    color: #141414;
    cursor: pointer;
    font-size: 2rem;
  }

  .input__center > input {
    text-indent: .3rem;
    flex: 1;
    border: 0;
    width: 100%;
    height: 100%;
    font-size: 1.3rem;
    color: #3b3b3b;
    outline: none;
  }

  .input__right {
    padding-left: .5rem;
    padding-bottom: .3rem;
    border-bottom: 1px solid #E9E9E9;
  }

  .icon-qingchu {
    color: #E9E9E9 !important;
  }

  .input-tip {
    margin-top: .3rem;
    margin-left: 2.45rem;
    font-size: 1rem;
  }

  .input-tip i {
    font-size: 1rem;
  }

  .input-tip--info {
    color: #BFBFBF;
  }

  .input-tip--success {
    color: #5CD18B;
  }

  .input-tip--warning {
    color: #FFC53D;
  }

  .input-tip--error {
    color: #FF7875;
  }
</style>


Хорошо, на данный момент наш пользовательский интерфейс закончен. Вы также можете ввести текст... неплохо

На данный момент возникла проблема:Прежде чем мы сможем напрямую v-model привязать значение входных двусторонних данных. Теперь ввод завернут внутрь компонента. Так как же нам связать ввод внутри дочернего компонента с родительским компонентом? ?

Долго искал туториал, нашел такую ​​операцию:

При добавлении атрибута v-модели к компоненту значение используется как атрибут компонента по умолчанию, а затем значение «вход» используется в качестве имени события при привязке событий к компоненту.

Ага, приятно говорить. Тогда мы можем написать это так:

<input :type="textType" title="" v-model="inputValue"
       @input="$emit('input', inputValue)">

export default{
  data() {
    return { 
     inputValue: "" //子组件内绑定一遍。等会要用
     }
   },
  }

Внешний вызов:

<zb-input v-model="phoneLogin.phone.value">

Закончено. Таким образом, вызывающая сторона родительского компонента может привязываться к значению поля ввода.




Хорошо, тогда мы начинаем делать функцию «Очистить одним ключом»

Поскольку значение, которое мы передаем, является двусторонними связанными данными в дочернем компоненте, который идет. Таким образом, теоретически нам нужно только очистить переменные, связанные с данными.

this.inputValue = '';

Но с этим будет проблема, дочерний компонент опустел, а родительский компонент все еще сохраняет значение.

Затем мы будем подражать вышеописанной практике и снова $emit~~~

clearInputValue() {
  this.inputValue = ''; //清空输入框的值
  this.$nextTick(function () { //在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM
    this.$emit('input', this.inputValue); //执行传出操作
  });
},

Эта функция реализована. Как показано ниже (цвет кнопки очистки слишком светлый. Программное обеспечение для записи анимации не видит ее ~~~ Извините)



Хорошо, тогда реализуем функции «показать» и «скрыть» пароля.




Эта функция также более интересна. Это не так просто, как изменить тип поля ввода на пароль. Он также может восстановить тип ввода, переданный ранее.

Сначала мы определяем реквизит:

inputType: { //输入框类型
  default: 'text'
}
canHide: {  //是否支持隐藏值
  required: false,
  default: false
},

Этот реквизит получает желаемый тип ввода от родительского компонента. Если нет, текст по умолчанию

Затем скопируйте синонимическую переменную в data. Сохраняйте опору как ссылку, данные несут ответственность за внутренние изменения~~~

textType: this.inputType //从props里接收初始值
isHideValue: false //现在是否隐藏输入框值

Затем очистите событие:

hideInputValue() {
  if (this.textType === this.inputType) { //如果props内和data内相等。说明是没隐藏状态
    this.textType = "password"; //让他变为password类型
    this.isHideValue = true; //控制隐藏按钮的类名。更换icon
  } else {
    this.textType = this.inputType; //替换为初始化的type
    this.isHideValue = false;
  }
}

Кнопки:

<i class="iconfont"
   :class="[{'icon-yanjing_yincang_o':!isHideValue},{'icon-yanjing_xianshi_o':isHideValue}]"
   @click="hideInputValue" v-show="canHide && inputValue"></i>


Вот и все! !


Теперь, когда мы сделали ввод, давайте сделаем это в конце~~

Пусть он поддерживает проверку пользовательских правил


Договариваясь с боссом, были временно выбраны для поддержки следующие правила:


1. lengthRange: объект поддерживает максимальный, минимальный максимум и минимум

2. регулярное: стандартное регулярное выражение

3. требуется: требуется ли логическое значение


Формат данных примерно такой:

regex: {
  required:false,
  lengthRange: {
    max: 11,
    min: 1
  },
  regular: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/
}

Затем передайте его через реквизит:

regexObject: { //校验对象
  required: false
}

:regexObject="regex"


Затем проводятся подготовительные работы, и начинается подготовка к проверочным работам.

Последовательность проверки проверяется в соответствии с очередью. Возвращайте результаты проверки соответственно. не указан выпуск

Проверьте, если требуется:

reg_required(value) {
  if (this.regexObject.required) { //如果有required这个字段
     return !!value //返回value是否有值
  } else {
    return null; //代表没填required这个字段
  }
},

Советы: "!!" часто используется для оценки типа, а логическая инверсия выполняется после первого шага !(переменная). Простое понимание состоит в том, чтобы определить, имеет ли переменная значение.

Эквивалент "value!=null&&typeof(value)!=undefined&&value!='' "

Проверка регулярного выражения:

reg_regular(value) {
  if (this.regexObject.regular) { //如果有regular这个字段
    return this.regexObject.regular.test(value); //返回校验的结果
  } else {
    return null; //代表没填regular这个字段
  }
},

Проверка длины:

reg_lengthRange(value) {
  if (this.regexObject.lengthRange) { //如果有lengthRange这个字段
    return value.length >= this.regexObject.lengthRange.min //如果value的长度大于等于预定最小值
      && value.length <= this.regexObject.lengthRange.max //如果value的长度小于等于预定最大值
  } else {
    return null; //代表没填lengthRange这个字段
  }
},


основной метод входа

regex(value) {
  let val = value.toString(); //统一转成字符串。防止没有length属性
  let info = {}; //空对象
  info.value = val; //一块把输入框的值传出去
  if (this.regexObject) { //如果props传了校验对象
    info.required = this.reg_required(val);
    info.regular = this.reg_regular(val);
    info.lengthRange = this.reg_lengthRange(val);
  }
  return info;
},


Наконец, вызывается в поле ввода событие вне фокуса (размытие):

inputReg() {
  console.log(this.regex(this.inputValue));
},


приставка:



Почувствуй это сам~~~

Потом нашел баг, хотя максимальный диапазон ввода определен, но его превышение только подсказывает, что ввод не запрещен


Итак, часы прослушивают inputValue

inputValue(){
  if (this.regexObject && this.regexObject.lengthRange) {
    if (this.inputValue.length > this.regexObject.lengthRange.max) { //如果输入框长度大于了既定最大长度
      this.inputValue = this.inputValue.slice(0, this.regexObject.lengthRange.max);//从0开始截取。截到最大长度
      return false;
    }
  } else {
    return false;
  }
}

Поскольку html5 удалил атрибут maxlength..... так что только перехват строки


Вот такой вход начального уровня готов! ! Функция вполне практичная


В следующей статье будет написана реализация компонента Tab. Всем хороших выходных~~~ Продолжайте писать в воскресенье вечером