Продолжая предыдущую статью, фреймворк проекта, который упорно трудился несколько дней, наконец-то доступен. Вы можете начать писать страницы прямо сейчас?
Раз босс сказал, давайте сами напишем 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..... так что только перехват строки
Вот такой вход начального уровня готов! ! Функция вполне практичная