首先,向大家说声抱歉.由于之前的井底之蛙,误认为 vue.js 还远没有覆盖到二三线城市的互联网小厂里.现在我错了,从我司的前端技术选型之路便可见端倪.以太原为例,已经有不少公司陆续开始采用 vue.js 作为他们公司前端的技术栈,前后端分离正搞得热火朝天,还有更多的公司正在来时的路上.所以说,还在校的童鞋和仍在培训的萌新们,Vue 已经成为现在前端的标配技能之一,为防止掉队,跟着闰土大叔学起来吧.
接下来,正文从这开始~
先来了解下当前的行业背景:
随着 SPA,前后端分离的技术架构在业界越来越流行,前端的业务复杂度也越来越高,导致前端开发者需要管理的内容,承担的职责越来越多,这一切,使得业界对前端开发方案的思考多了很多,以 react,vue 等框架为代表推动的组件化开发模式越来越被开发者认可,这种模式极大的降低了我们开发与维护的成本.
最近一段时间,我也在研究 Vue,在网上看了那么多基于 Vue 的组件,何不自己也来造个小轮子,有了这个想法后,撸子袖子就是干.本文提供代码仅仅是提供而已,重要的是思路.
用Vue造个组件轮子吧-闰土大叔
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
如果你掌握了 Vue 的组件知识,相关的指令,事件,花点时间你也可以造出这么个入门级的小轮子.如果这篇文章只是单纯的贴出组件轮子代码那也太 easy 了.接下来,抛出造轮子实践背后带来的一些思考.
</title>
</head>
<body>
<div id="app">
<input-number v-model="value" :max="20" :min="0">
</input-number>
</div>
<script src="js/vue.js">
</script>
<script>
function isValueNumber(value) {
return (/(^-?[0-9]+\.{1}\d+$)|(^-?[1-9][0-9]*$)|(^-?0{1}$)/).test(value + '');
}
Vue.component('input-number', {
template: ` < div class = "input-number" > <input type = "text"lue = "currentValue"ange = "handleChange" = "input"ydown = "show($event)" / ><button@click = "handleDown": disabled = "currentValue <= min" > -</button>
<button @click="handleUp" :disabled="currentValue >= max">+</button > </div>
`,
props:{
max:{
type:Number,
default:Infinity
},
min:{
type:Number,
default:-Infinity
},
value:{
type:Number,
default:0
},
step:{
type:Number,
default:5
}
},
data: function(){
return {
currentValue: this.value
}
},
watch:{
currentValue:function(val){
this.$emit('input',val);
},
value:function(val){
this.updateValue(val);
}
},
methods:{
handleDown: function(){
if(this.currentValue <= this.min) return;
this.currentValue -= this.step;
},
handleUp: function(){
if(this.currentValue >= this.max) return;
this.currentValue += this.step;
},
updateValue:function(val){
if(val > this.max) val = this.max;
if(val < this.min) val = this.min;
this.currentValue = val;
},
handleChange:function(event){
var val = event.target.value.trim();
var max = this.max;
var min = this.min;
if(isValueNumber(val)){
val = Number(val);
this.currentValue = val;
if(val > max){
this.currentValue = max;
}else if(val < min){
this.currentValue = min;
}
}else{
event.target.value = this.currentValue;
}
},
show:function(ev){
console.log(ev.keyCode)
if(ev.keyCode == 38){
this.handleUp();
}else if(ev.keyCode == 40){
this.handleDown();
}
}
},
mounted:function(){
this.updateValue(this.value);
this.$refs['input'].focus();
}
})
var app = new Vue({
el:'#app',
data:{
value:5
}
})
/
</script>
</body>
</html>
第一问:
vue 已经挂载的组件怎么初始化里面的 data?
能问出这个问题的童鞋,说明你已经迷上了 Vue.按照源码里讲的,vue 将数据绑定到组件的原理分为三个步骤: 当实例化一个 Vue 构造函数,会执行 Vue 的 init 方法,在 init 方法中主要执行三部分内容,一是初始化环境变量,二是处理 Vue 组件数据,三是解析挂载组件.以上三部分内容构成了 Vue 的整个执行过程.
第二问:
vue 注册组件为什么要必须发生在根实例初始化前?
可能你已经熟读 Vue 官方 API 文档,但是这个问题你考虑过么.如果在 Vue 根实例初始化之后才注册组件会发生什么?如果你有兴趣,我可以等你实践 30 秒再说我的想法.
30 秒时间到了,在等你的时候,我又实践了一遍.是的,报错了.大意是,未知的自定义元素: - 你是否正确注册了组件?对于递归组件,请确保提供 name 选项.
我曾翻阅过官网 API 文档,也曾阅览过相关的书籍,但里面都是简单的提了一句:
这个问题无解么,不是的.其实你仔细想想报错信息,你应该会泯然一笑,说的通俗点,这就像坐高铁,买了票才能上.因为实例化的时候会尝试找这个组件,你不提前注册就找不到了.如果硬要深究,只能去看源码了.
第三问:
这个数字输入框组件网上很常见,在此基础上你有做什么扩展么?
是的,与网上的数字输入框组件不同的,我做了两个扩展.
第一个扩展:input 框自动获取焦点,在输入框聚焦时,监听键盘上下按键的操作,相当于加 1 或者减 1.
实现的思路,在 input 输入框上定义一个 ref 为 input 引用,然后在模板渲染完毕之后,在 mounted 钩子里,通过 $refs 查找到对应的 ID:input,然后 focus.获取完焦点之后,接下来就是如何监听键盘上下按键的操作.首先,我们通过 keydown 事件绑定一个 show() 方法,里面传一个 $event 参数,然后在子组件的 methods 选项内创建一个 show 方法.我们都知道,键盘上的上键对应的 keyCode 码是 38,下键对应的是 40. 有了这个之后,我们做一个条件判断(上加下减),如果 event 的 keyCode 码为 38,就调用 handleUp() 方法,如果是 40,就调用 handleDown() 方法.至此,监听键盘上下键的按下进而操作 input 数值的扩展完成.
第二个扩展:给组件增加一个控制步伐的 prop——step,比如设置为 10,点击加号按钮,一次增加 10.
继续说说我的思路,这个就相对来说比较简单了,首先在 props 选项内定义一个 step 对象,类型设置为 Number,默认值设置为 5.然后将 methods 里面的 handleDown 和 handleUp 里面将 this.currentValue +/-= (具体的数值)替换为 this.step.相当于进一步封装了它的可用性.至此,所有扩展完成.
后记
自己曾经求职面试前端,因不会 Vue 框架而被淘汰,而且不止一次,也曾因此赋闲半年在家.所以,事不过三,我要抓紧时间学会它,以及它的全家桶.有原则有危机感的人,往往都是之前吃过大亏的人.他们知道犯错误的代价,所以不敢触碰这个红线.愿我走过的路踩过的坑,你们不会再踩一遍,才会哭着鼻子记住这个教训.以铜为镜, 可以正衣冠; 以人为镜, 可以明得失.在之后的日子里,我还会继续更新 vue 相关的文章,愿我们都做一个爱思考的孩子.前端路上,we are not alone.
想了解我的更多动态?欢迎关注我的公众号:闰土大叔,或者添加我的个人微信号:wxd91traveler,期待与你发生一段纯纯的友谊.
来源: https://juejin.im/post/5a573abbf265da3e3b7a7148