前言
自从几年前React、Angular、Vue兴起,业界就开始有一个观点是:终于可以摆脱jQuery了!但是,其实很奇怪,一个MVVM框架能取代一个库吗?
jQ虽然逐渐走向消亡,但是消灭jQ的绝对不会是MVVM框架,因为两者根本是两码事。
jQ消亡的原因很多,比如原生JS的DOM标准进行了几次升级,已经跟jQ的选择器系统接近,而Ajax、异步、动画这三大块,也有很棒的原生JS支持和独立库,所以jQ的优势被消磨殆尽,但是,jQ唯独跟MVVM没一毛钱关系。
如果说,jQ跟Vue有什么冲突,其实就是在DOM上:
Vue有一套自己的虚拟DOM系统,因此,jQ对DOM做的任何修改,默认前提下,都不会被Vue所承认,也就是说,Vue并不知道、也不关心jQ对界面做了什么修改,等到Vue对DOM做了后续修改,这时候前面jQ做的任何修改都会被抹平。这就是Vue与jQ的冲突。
那么,这种冲突是无法解决的么?显然不是。一个很简单的做法就是:
将一片DOM节点划归jQ,也就是说,Vue不打算管这一片节点,交给jQ全权负责。同时,jQ需要从Vue读取数据,呈现到UI中,jQ操作DOM之后,必须将操作结果通知Vue,由Vue保存结果。看到了吧?双向绑定。
除此之外,再结合上生命周期,后加载jQ,保证jQ始终被Vue所管理,等等,具体不多说。下面用一个例子来说明。
全网通缉一个适用于Vue的range-slider插件
最近在做的一个小型Vue项目,其中需要一个range-slider插件,要像这样子:
image.png刚开始,我也尝试过自己写一个,但是里面要注意的细节还是很多的,所以决定搜一个。然而,我尝试搜索Vue版本的这种插件,搜了1个小时也没找到,找到的一律是jQ版本的,好消息是jQ版本的插件非常成熟,比如Ion.RangeSlider,它除了需要CSS定制一下,其他像options完全够用,可以说是想要做到,心想事成。这么OK的插件只有一个问题:它不是Vue版本。
怎么办?
用呗。
安装
官网:http://ionden.com/a/plugins/ion.rangeSlider/
npm install jquery --save
npm install ion-rangeslider --save
编写子组件“IonRangeSlider.vue”
为了方便管理,rangeslider写成一个vue组件,大致如下:
<template>
<div class="ion-range-slider">
<input type="text" ref="range_input" value="" />
</div>
</template>
<script>
import jQuery from 'jquery'
import 'ion-rangeslider'
import 'ion-rangeslider/css/ion.rangeSlider.css'
import 'ion-rangeslider/css/ion.rangeSlider.skinHTML5.css'
export default {
model: {
prop: 'averagePriceRange',
event: 'slideFinish'
},
props: ['averagePriceRange'],
mounted () {
jQuery(this.$refs.range_input).ionRangeSlider({
type: "double",
min: 0,
max: 100,
from: this.averagePriceRange.from,
to: this.averagePriceRange.to,
hide_min_max: true,
prefix: '¥',
max_postfix: '+',
extra_classes: '',
onFinish: (data) => {
console.log(data)
this.$emit('slideFinish', {from: data.from, to: data.to})
}
})
}
}
</script>
template
template这块代码很简单,<input type="text" ref="range_input" value="" />
是Ion.RangeSlider要求的,看手册即可。
import
import jQuery from 'jquery'
import 'ion-rangeslider'
import 'ion-rangeslider/css/ion.rangeSlider.css'
import 'ion-rangeslider/css/ion.rangeSlider.skinHTML5.css'
前两行不解释,但是引入css的办法,插件手册里并没有写,需要我自己看node_modules的ion-rangeslider文件夹里面的文件架构,然后引入。皮肤文件根据自己需要选一个即可。
export
- mounted,这个最好理解,纯jQ和jQ插件的知识,不解释。
data
的内容打印了自己看即可。唯独只有一句this.$emit('slideFinish', {from: data.from, to: data.to})
,后面解释。 - props,因为我的项目是需要价格区间,所以变量名为
averagePriceRange
。准备从父组件接受这个变量,它的数据架构就是{from: data.from, to: data.to}
。 - model,这个要划重点。model是一个不常用属性,手册是https://cn.vuejs.org/v2/api/#model。说白了,就是它跟$emit()配合,将数据传递给父组件。
编写父组件
父组件这块,我只在下方写出跟这次尝试相关的代码。
<template>
<div class="range-warpper">
<ion-range-slider
v-model="averagePriceRange"
></ion-range-slider>
</div>
</template>
<script>
import IonRangeSlider from '@/components/common/IonRangeSlider.vue'
export default {
components: { IonRangeSlider },
data () {
return {
averagePriceRange: {from: 0, to: 100}
}
}
}
</script>
template
template中的要点只有一个:v-model="averagePriceRange"
,也就是给子组件双向绑定这个变量。
script
script代码完全不用解释。
效果
效果跟插件手册的范例一模一样。
怎么确定实现了双向绑定?
测试父向子传值
将父组件的data的averagePriceRange初始值改成{from: 33, to: 77}
,界面中会看到,左右指针的位置指向了33和77。
测试子向父传值
先打开浏览器的Vue.js devtools插件,调到Vue,找到我们的父组件,看到右侧数据已经是:
image.png当然,此时UI中指针也是33和77。
然后拖动指针,比如拖到24和86,然后观察Vue.js devtools插件的data,会发现也变成了24和86。我就不再截图了。
结论
Vue.js里使用jQuery是完全可行的,而且完全符合Vue的工作思想,本质上,将jQ视为一个对Vue适配度不高的Vue插件就行了,双向绑定工作需要你自己来完成而已。
谢谢。
网友评论