Front-end development of the students should is not unfamiliar to Element UI, and daily development, how many there are some components can not fully meet our requirements, or want to additional features on the basis of the original component, when need additional something not very complex, using the Vue custom instruction to do this, It will be very elegant

prospects

We know that Element UI’s EL-input component type is text. When we get a textarea, we can display the word count by setting the show-word-limit attribute. However, the version of Element UI used in our current project is 2.5.21, which does not have this attribute, and it is not convenient for us to upgrade Element UI version for the time being, and the product manager insists on this small item, so how to solve this problem

This little feature is actually quite simple, as follows

<template> <div class="el-input-wrap"> <el-input type="textarea" :autosize="{ minRows: 4, maxRows: 4 }" v-model="desc" maxlength="30"> </el-input> <span class="el-input-count">{{ desc.length }}/30</span> </div> </template> <script type="text/ecmascript-6"> export default { data() { return { desc: '' } } } </script> <style> .el-input-wrap { position: relative; } .el-input-count { position: absolute; The line - height: 1.5; color: #909399; background: #fff; font-size: 12px; bottom: 5px; right: 10px; } </style>Copy the code

By manually adding the parent element to set the location attributes, and then adding the SPAN element to set the location and style to show the dynamic length limits, you can achieve exactly the same effect as the new version of show-word-limit. However, there is still a bit of trouble, and you have to do this again every time you use it. It is not easy to extract and encapsulate components, so how about using custom instructions to do it?

Train of thought

The final effect is expected to be achieved by an instruction such as

<el-input 
  v-limit
  type="textarea"    
  :autosize="{ minRows: 4, maxRows: 4 }" 
  v-model="desc"
  maxlength="30">
</el-input>
Copy the code

What’s missing? What do we need to do?

1. Create a parent element and set the location property. This step is the key to showing whether the text is located in the lower right corner of the input box

2. Create a SPAN element setting style to show the effect

3. Fill the span element with the length of the value of the el-input binding

4. Update the span element every time the length of the value of the EL-Input binding changes

Now that we have the idea, it’s not too complicated, so let’s see, how do we write this code

Actual code

We first create a JS file showwordlimite.js, then export an object that can register instructions, and then, while the hook function is inserted, we implement the first step, creating a parent element and setting the position properties

export default{
  inserted: function () {
    let wrap = document.createElement('div')
    wrap.style.position = 'relative'}}Copy the code

Since it is the parent element, we also need to insert the el-input element that uses the directive into the parent element and retrieve the DOM element via the hook argument

export default{
  inserted: function (el) {
    let wrap = document.createElement('div')
    wrap.style.position = 'relative'
    
    el.parentNode.replaceChild(wrap, el)
    wrap.appendChild(el)
  }
}
Copy the code

Now that we’re done with the first step, go ahead and create a SPAN element, style it, and insert it into the parent element you just created

export default{
  inserted: function (el) {
    let wrap = document.createElement('div')
    wrap.style.position = 'relative'
    
    el.parentNode.replaceChild(wrap, el)
    wrap.appendChild(el)
    
    let oSpan = document.createElement('span')
    oSpan.style.lineHeight = 1.5
    oSpan.style.color = '# 909399'
    oSpan.style.position = 'absolute'
    oSpan.style.background = '#FFF'
    oSpan.style.fontSize = '12px'
    oSpan.style.bottom = '5px'
    oSpan.style.right = '10px'
    oSpan.innerText = '0/30'
    
    wrap.appendChild(oSpan)
  }
}
Copy the code

Notice that the innerText value, which is a variable, is determined by the length of the value of the el-input value, so we need to use the dynamic instruction, and when we use the instruction, we pass that value, for example

<el-input 
  v-limit="desc.length"
  type="textarea"    
  :autosize="{ minRows: 4, maxRows: 4 }" 
  v-model="desc"
  maxlength="30">
</el-input>
Copy the code

Back to showwordlimite.js, how do I receive this value? This can also be obtained through the binding parameter of the hook. If it is not clear, please refer to the official Vue documentation for the custom instruction, which is clearly stated. Once obtained, replace the value of the SPAN element

export default{
  inserted: function (el, binding) {
    let wrap = document.createElement('div')
    wrap.style.position = 'relative'
    
    el.parentNode.replaceChild(wrap, el)
    wrap.appendChild(el)
    
    let oSpan = document.createElement('span')
    oSpan.style.lineHeight = 1.5
    oSpan.style.color = '# 909399'
    oSpan.style.position = 'absolute'
    oSpan.style.background = '#FFF'
    oSpan.style.fontSize = '12px'
    oSpan.style.bottom = '5px'
    oSpan.style.right = '10px'
    Value is equal to the length of the value of the el-input component using the directive, where the ES6 string template is concatenated
    oSpan.innerText = `${binding.value}/ 30 `
    
    wrap.appendChild(oSpan)
  }
}
Copy the code

OK, so far, you can try it out. Import and register the directive in man.js

// main.js If you do not use vue-CLI scaffolding, you need to find the corresponding import file registration
import showWordLimit from '@/directive/showWordLimit'
Vue.directive('limit', showWordLimit)
Copy the code
<! <el-input v-limit="desc.length" type="textarea" :autosize="{minRows: 4, maxRows: 4; 4 }" v-model="desc" maxlength="30"> </el-input>Copy the code

This time, show the effect of value, is not updated with the content of the input box length transform, although is the processing of the transfer text box content length, but in the inserted inside, it will only perform a, if the length of the text box default value is 10, then it shows will be 10/30, then we can edit the content, The length has changed, and it is still 10/30. If you want to update the display value every time you edit, you need to use another hook function update

export default{
  inserted: function (el, binding) {
    let wrap = document.createElement('div')
    wrap.style.position = 'relative'
    
    el.parentNode.replaceChild(wrap, el)
    wrap.appendChild(el)
    
    let oSpan = document.createElement('span')
    oSpan.style.lineHeight = 1.5
    oSpan.style.color = '# 909399'
    oSpan.style.position = 'absolute'
    oSpan.style.background = '#FFF'
    oSpan.style.fontSize = '12px'
    oSpan.style.bottom = '5px'
    oSpan.style.right = '10px'
    Value is equal to the length of the value of the el-input component using the directive, where the ES6 string template is concatenated
    oSpan.innerText = `${binding.value}/ 30 `
    
    // Add an ID to make it easier to get it in the update lifecycle function
    oSpan.setAttribute('id'.'oSpan')
    
    wrap.appendChild(oSpan)
  },
  update: function (el, binding) {
    let oSpan = document.getElementById('oSpan')
    oSpan.innerText = `${binding.value}/ 30 `}}Copy the code

Numerical should now display effect has been achieved real-time updates, attentive students should find, there is a place there are omissions, that the maximum limit of characters is to show the effect of Numbers, is now a fixed die 30, that if you want to limit for other numerical characters, not line, that also is very simple to solve this problem, will be passed values, to be in the form of an array

<el-input 
  v-limit="[desc.length, 50]"
  type="textarea"    
  :autosize="{ minRows: 4, maxRows: 4 }" 
  v-model="desc"
  maxlength="30">
</el-input>
Copy the code
export default{
  inserted: function (el, binding) {
    let wrap = document.createElement('div')
    wrap.style.position = 'relative'
    
    el.parentNode.replaceChild(wrap, el)
    wrap.appendChild(el)
    
    let oSpan = document.createElement('span')
    oSpan.style.lineHeight = 1.5
    oSpan.style.color = '# 909399'
    oSpan.style.position = 'absolute'
    oSpan.style.background = '#FFF'
    oSpan.style.fontSize = '12px'
    oSpan.style.bottom = '5px'
    oSpan.style.right = '10px'
    Value is equal to the length of the value of the el-input component using the directive, where the ES6 string template is concatenated
    oSpan.innerText = `${binding.value[0]}/${binding.value[1]}`
    
    // Add an ID to make it easier to get it in the update lifecycle function
    oSpan.setAttribute('id'.'oSpan')
    
    wrap.appendChild(oSpan)
  },
  update: function (el, binding) {
    let oSpan = document.getElementById('oSpan')
    oSpan.innerText = `${binding.value[0]}/${binding.value[1]}`}}Copy the code

So far, even if the custom instruction is completely done, of course, it is not difficult. The purpose of this article is to give guidance to some students who have not been exposed to the application of custom instruction, to tell a complete application process and ideas, hoping to help some people, but also keep their own notes