Following on from the previous article, the project framework that I’ve been working on for days is finally ready to work. Can we start writing pages now?

Since our boss says we should write the UI framework ourselves, let’s do it ourselves.


Although it was nice to say yes. When it comes to writing, I don’t know where to start first

Then we’ll do it little by little. Start with the component framework.


First, arrange the UI framework directory. After a long chat with my boss, I finally decided to use this directory structure:



The red arrow represents where the business Components are stored in the project. Such as head navigation, personal information card, etc

The green arrows represent where the business components (Framework Components) store the underlying framework components in the project. Such as buttons, input boxes, switches and so on

The blue arrow is the exported file. Exporting all components for easy invocation (more on that later in the article)



Okay, so let’s start with input



Writing the input component

Let’s start with the renderings:



It looks something like this. Very simple UI, functionality is enough. (Here give UI brother’s work a thumbs up)

I split it up to look like this with different slots in each color box.



The code roughly looks like this:

<template>
  <div class="input-wrapper">
    <div class="input-content">
      <div class="input__left">
        <slot name="left"></slot> // red box 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 ></ div> <div class="input__right">
        <slot name="right"></slot> //input custom area on the right. </div> <div class="input-tip">
      <slot name="tip"</slot> </div> </div> </template>Copy the code

Use flex layout for CSS. Font/icon size, element spacing using REM layout class naming using 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.rem; } .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%; The font - size: 1.3 rem; 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.45 rem; 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>
Copy the code



OK, so now we’re done drawing our UI. You can also type text… Great!

Here’s a problem: Previously we could data-bind the value of the input directly to the V-Model. Input is now wrapped within the component. So how do we bind the input in the child component in the parent?

After half a day of searching for the tutorial, I found this operation:

When you add a V-Model property to a component, you default to value as the component property, and then to the ‘input’ value as the event name when you bind an event to the component

Ah ha, that explains it. So we can write it like this:

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

export default{
  data() {
    return { 
     inputValue: "" // Bind inside the child component. Later want to use}}},Copy the code

External calls:

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

And we’re done. This allows the parent component caller to bind to the value of the input box






OK, let’s do the “one Click clear” function

Since the value we are passing out is a two-way bound data within the child component. So in theory all we need to do is empty the variables that are bound to the data

this.inputValue = ' ';Copy the code

The problem with this is that the child component has been emptied and the parent component still retains the value.

Then let’s imitate the above and emit ~~~ again

clearInputValue() {
  this.inputValue = ' '; // Clear the input field value this.$nextTick(function() {// Use after data modification$nextTick, you can get the updated DOM this in the callback.$emit('input', this.inputValue); // Perform an outgoing operation}); },Copy the code

And that’s it. The clear button is too light. GIF recording software can not be seen ~~~ sorry)




Ok, so let’s implement the password “show” and “hide” function





This feature is also interesting. It’s not just a matter of changing type to password. You can also restore the input type that was passed in

First, let’s define an props:

InputType: {// Input box type default:'text'} canHide: {// Whether hidden values are supported required:false,
  default: false
},

Copy the code

This props receives the desired input type from the parent component. If not, default text

Then copy a copy of the same variable into data. Keeping prop as reference, data is responsible for internal changes ~~~

TextType: this.inputType // receive the initial value isHideValue from props:false// Now whether to hide input field valuesCopy the code

Then clear the event:

hideInputValue() {
  if(this.textType === this.inputType) {// if the props and data are equal. No hidden state this.textType ="password"; // Make it password type this.ishideValue =true; // The name of the class that controls the hidden button. Change the icon}else{ this.textType = this.inputType; // Replace with initializedtype
    this.isHideValue = false; }}Copy the code

Buttons:

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


And we’re done!!


Since we do input, let’s do it all ~~

Let him support custom rule validation


After negotiation with my boss, I have selected the following rules for support:


1. LengthRange: Object supports the maximum and minimum values of min

2. Regular: Regular expression

3. Required: Boolean Specifies whether this parameter is mandatory


The data format looks something like this:

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}$/
}Copy the code

And pass it through props:

RegexObject: {// Verify object required:false
}

:regexObject="regex"Copy the code


Then the preparation was done, and it was time to prepare the calibration

Check by queue. Return the verification results respectively. No release is specified

Mandatory check:

reg_required(value) {
  if(this. RegexObject. Required) {/ / if this field is requiredreturn!!!!! Value // Return whether value has a value}else {
    returnnull; // the required field is not entered}},Copy the code

Tips: “!!!!! “Often used to make type judgments in the first step! And then do the logical inversion. The simple idea is to determine whether the variable has a value.

Equivalent value!” =null&&typeof(value)! =undefined&&value! = “”

Regular expression check:

reg_regular(value) {
  if(this.regexObject.regular) {// If there is a regular fieldreturnthis.regexObject.regular.test(value); // Return the result of the check}else {
    returnnull; // Regular is not included in the field}},Copy the code

Length check:

reg_lengthRange(value) {
  if(this. RegexObject. LengthRange) {/ / if you have lengthRange this fieldreturnValue. The length > = this. RegexObject. LengthRange. Min / / if the value is greater than or equal to the length of the book value. The minimum && length < = Enclosing regexObject. LengthRange. Max / / if the value less than or equal to the length of the predetermined maximum}else {
    returnnull; // the field lengthRange is not filled}},Copy the code


Main entrance method

regex(value) {
  letval = value.toString(); // Convert to a string. Prevents no length attributeletinfo = {}; // Empty object info.value = val; // Pass out the value of the input fieldifRequired = this.reg_required(val); (this.regexObject) {// If props passes the validation. info.required = this.reg_required(val); info.regular = this.reg_regular(val); info.lengthRange = this.reg_lengthRange(val); }return info;
},Copy the code


Finally, the input box is called within the blur event:

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


Console:




Feel ~~~ for yourself

Then I found a bug, although the maximum input range is defined, beyond it just prompts not to disable input


So watch listens on the inputValue

inputValue() {if (this.regexObject && this.regexObject.lengthRange) {
    if(this. InputValue. Length > enclosing regexObject. LengthRange. Max) {/ / if the input frame length is greater than the established maximum length. InputValue = this.inputValue.slice(0, this.regexObject.lengthRange.max); // Cut from 0. I'm going to cut it to the maximum lengthreturn false; }}else {
    return false; }}Copy the code

Because HTML5 removed the maxLength attribute….. So you can only intercept strings


This is an entry level Input!! Function is more practical


The next article will write the implementation of Tab components. Have a great weekend everybody ~~ continue writing on Sunday night