回顾
上一篇文章中,我们搭建了 KendoUI 和 Vue.js 的集成开发环境,
并且提出了一个 kendoDropDownList 的集成方案:
- 父组件通过 props 传递相关配置到我们包装的 component
- 子组件通过触发事件来进行
现在,我们可以将该方案完善一下:
- 父组件通过 props 传递相关配置到 我们包装的 component
- 通过 v-model 对数据进行双向绑定
那么如何使用 v-model 指令呢?
仔细查阅Vue2的文档,会发现:
<input v-model="something">
只是
<input v-bind:value="something" v-on:input="something = $event.target.value">
的语法糖。
在Vue2的组件中,我们可以将以上写法简写为:
<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>
所以如果我们想让组件接受 v-model
指令,必须满足:
- 必须接受
value
属性
- 组件内部需要使用
input
事件把新的值带出来
所以现在就非常简单了:
- 使用 Node.js express 生成一个简单的数据源
- 我们希望在
kendoDropDownList
组件中调用 kendoDropDownList 模块的 init 方法,传入的option应该包括:dataSource
的描述(url
,httpMethod
或者直接是data
,valueField
,textField
),当前的 element(this.$el
),value
- 在
kendoDropDownList
的init
方法中添加相应的初始化方法 - 在
kendoDropDownList
的值改变的时候应该触发input
事件,并带上新的值 - 需要对组件中的
value
进行watch
。当value改变时,需要将该值带回kendoDropDownList
中
所以我们希望以如下方式调用我们的组件
<drop-down-list v-model="selectedValues.firstSelectValue" v-bind:dataSource="dropDownListOptions.dataSource"></drop-down-list>
使用 Node.js express 准备我们的数据源
首先,你需要新建一个express
应用程序
然后添加以下路由:
router.get('/dropDownListData', function (req, res, next) {
let data = [
{key: "option1", value: 1},
{key: "option2", value: 2}
];
setTimeout(()=>{res.json(data);}, 1000)
});
router.get('/dropDownListData2', function (req, res, next) {
let data = [
{key: "option3", value: 3},
{key: "option4", value: 4}
];
setTimeout(()=>{res.json(data);}, 1000)
});
setTimeout意为一个比较费时的取数据的操作。
然后你需要使用 cors 允许你的express
应用程序接受跨域请求
启动该应用。
包装 kendoDataSource 和 kendoDropDownList
本来本节只有包装
kendoDropDownList
,但是代码写了一半发现,KendoUI 的组件有很多都需要kendoDataSource
来提供数据源,所以我们也需要写一个kendoDataSource
的工厂来生成配置的dataSource
部分。
代码如下:
//文件:src/modules/kendoUi/kendoDataSource.js
function getKendoDataSource(dataSource){
let result = dataSource.url ?
_generateKendoRemoteDataSource(dataSource) :
_generateKendoObjectDataSource(dataSource);
return result;
}
function _generateKendoObjectDataSource(dataSource){
return dataSource.data;
}
function _generateKendoRemoteDataSource(dataSource){
return {
transport: {
read: {
type: dataSource.method,
dataType: "json",
url: dataSource.url,
}
}
}
}
export default {
getKendoDataSource
}
所以我们可以这样初始化kendoDropDownList:
//文件:src/modules/kendoDropDownList.js
import 'kendoUiStyles/kendo.common.min.css'
import 'kendoUiStyles/kendo.bootstrap.min.css'
import kendoDropDownList from 'kendoUi/kendo.dropdownlist.min'
import $ from 'jquery'
import kendoDataSource from "./kendoDataSource"
function init(option) {
let el = option.el;
let dropDownList = option.dataSource.url ? initWithDataSource(option) : initWithDataObject(option);
dropDownList.data("kendoDropDownList").value(option.value);
}
function initWithDataSource({dataSource, el, onValueChanged}) {
let kendoDropDownListOption = {
dataTextField: dataSource.dataTextField,
dataValueField: dataSource.dataValueField,
optionLabel: "---请选择---",
change: function (e) {
onValueChanged(this.value());
},
dataSource: kendoDataSource.getKendoDataSource(dataSource)
};
return $(el).kendoDropDownList(kendoDropDownListOption);
}
function initWithDataObject({dataSource, el, onValueChanged}) {
let kendoDropDownListOption = {
dataTextField: dataSource.dataTextField,
dataValueField: dataSource.dataValueField,
optionLabel: "---请选择---",
change: function (e) {
onValueChanged(this.value());
},
dataSource: kendoDataSource.getKendoDataSource(dataSource)
};
return $(el).kendoDropDownList(kendoDropDownListOption);
}
function updateSelectedValue({el, value}){
$(el).data("kendoDropDownList").value(value);
}
function updateDataSource({el, dataSource}){
console.log($(el).data("kendoDropDownList"));
let ds = kendoDataSource.getKendoDataSource(dataSource);
$(el).data("kendoDropDownList").setDataSource(ds)
}
export default {
init,
updateSelectedValue,
updateDataSource
}
其中,el
代表从 vue component 那边传来的当前的元素。
⚠️该文件只会执行一次(第一次被
import
的时候),所以不要在文件内部写全局变量。
⚠️代码还有重构的余地
构建自定义组件
于是,我们就可以在自定义组件中这样调用:
<!--文件: src/components/kendoDropDownList.vue-->
<template>
<div></div>
</template>
<script>
import kendoDropDownList from "../modules/kendoUi/kendoDropDownList"
function onValueChanged(value){
this.$emit("input", value);
}
function onMounted() {
let {dataSource, value} = this;
onValueChanged = onValueChanged.bind(this);
let option = {
dataSource,
value,
el: this.$el,
onValueChanged
};
console.log(option);
kendoDropDownList.init(option);
}
let props = {
data: Array,
dataSource: Object,
value: {}
};
function updateValue(newValue){
let el = this.$el;
let value = newValue;
kendoDropDownList.updateSelectedValue({el, value})
}
function updateDataSource(newDataSource){
let el = this.$el;
let dataSource = newDataSource;
kendoDropDownList.updateDataSource({el, dataSource})
}
export default {
name: "dropDownList",
mounted: onMounted,
props,
watch:{
value: updateValue,
dataSource: updateDataSource
}
}
</script>
至此,我们的第一个KendoUI组件就完成了。你可以这样调用它:
<template>
<div id="app">
<!--![](./assets/logo.png)-->
<!--<hello></hello>-->
<drop-down-list v-model="selectedValues.firstSelectValue" v-bind:dataSource="dropDownListOptions.dataSource"></drop-down-list>
<drop-down-list v-model="selectedValues.secondSelectedValue" v-bind:dataSource="dropDownListOpts2.dataSource"></drop-down-list>
<button v-on:click="changeFirstValue">修改第一个select的值为2</button>
<button v-on:click="changeFirstDataSource">将第一个的数据源修改为 /dropDownListData2</button>
</div>
</template>
<script>
import dropDownList from "./components/kendoDropDownList.vue"
let dropDownListOptions = {
value: 2,
dataSource: {
url: "http://localhost:3000/dropDownListData",
method: "GET",
dataTextField: "key",
dataValueField: "value"
}
};
let dropDownListOpts2 = {
dataSource: {
data: [
{key: "option1", value: 1},
{key: "option2", value: 2}
],
dataTextField: "key",
dataValueField: "value"
},
value: 2
};
let selectedValues = {
firstSelectValue :1,
secondSelectedValue: 2
};
let data = function () {
return {
dropDownListOptions,
dropDownListOpts2,
selectedValues
}
};
function changeFirstValue(){
this.selectedValues.firstSelectValue = 2;
}
function changeFirstDataSource(){
this.dropDownListOptions.dataSource = {
url: "http://localhost:3000/dropDownListData2",
method: "GET",
dataTextField: "key",
dataValueField: "value"
}
}
export default {
name: 'app',
components: {
dropDownList
},
methods: {
changeFirstValue,
changeFirstDataSource
},
data
}
</script>
那么,效果应该是这样的:
在这个例子中,我们使用了v-model
,实现了子组件与父组件数据的双向绑定,很简单,是不是?
之后笔者还会对KendoUI的其他组件进行扩充,事实上,还有很多事情我们没有做。比如,如果我们要使用kendoUI的Template
功能,就可能还要做一些事情,把Template
给放出来。
其实也简单,开发出来一些预置的Template
,然后要用的时候往里面丢就可以了。
后续
和 kendoDropDownList
相比,kendoGrid
封装起来可能会稍微复杂一些(主子列表、特殊标记某一列等),可能也需要舍弃一些功能,但是工作流程都是一样的:
- 写一个专门初始化
kendoGrid
的模块,该模块需要根据当前的DOM对象(el
)生成一个kendoGrid
- 新建一个Vue组件,引入该模块,并初始化好
kendoGrid
- ⚠️需要注意的是,
kendoGrid
需要频繁变化数据源(比如做筛选操作的时候),所以需要用一个巧妙的方式来解决这个问题(最好不要破坏后台的RESTFul
架构)。
欢迎讨论😁