回顧
上一篇文章中,我們搭建了 KendoUI 和 Vue.js 的集成開發(fā)環(huán)境,
并且提出了一個 kendoDropDownList 的集成方案:
- 父組件通過 props 傳遞相關配置到我們包裝的 component
- 子組件通過觸發(fā)事件來進行
現(xiàn)在,我們可以將該方案完善一下:
- 父組件通過 props 傳遞相關配置到 我們包裝的 component
- 通過 v-model 對數(shù)據(jù)進行雙向綁定
那么如何使用 v-model 指令呢?
仔細查閱Vue2的文檔,會發(fā)現(xiàn):
<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屬性
- 組件內(nèi)部需要使用
input事件把新的值帶出來
所以現(xiàn)在就非常簡單了:
- 使用 Node.js express 生成一個簡單的數(shù)據(jù)源
- 我們希望在
kendoDropDownList組件中調用 kendoDropDownList 模塊的 init 方法,傳入的option應該包括:dataSource的描述(url,httpMethod或者直接是data,valueField,textField),當前的 element(this.$el),value - 在
kendoDropDownList的init方法中添加相應的初始化方法 - 在
kendoDropDownList的值改變的時候應該觸發(fā)input事件,并帶上新的值 - 需要對組件中的
value進行watch。當value改變時,需要將該值帶回kendoDropDownList中
所以我們希望以如下方式調用我們的組件
<drop-down-list v-model="selectedValues.firstSelectValue" v-bind:dataSource="dropDownListOptions.dataSource"></drop-down-list>
使用 Node.js express 準備我們的數(shù)據(jù)源
首先,你需要新建一個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意為一個比較費時的取數(shù)據(jù)的操作。
然后你需要使用 cors 允許你的express應用程序接受跨域請求
啟動該應用。
包裝 kendoDataSource 和 kendoDropDownList
本來本節(jié)只有包裝
kendoDropDownList,但是代碼寫了一半發(fā)現(xiàn),KendoUI 的組件有很多都需要kendoDataSource來提供數(shù)據(jù)源,所以我們也需要寫一個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 那邊傳來的當前的元素。
??該文件只會執(zhí)行一次(第一次被
import的時候),所以不要在文件內(nèi)部寫全局變量。
??代碼還有重構的余地
構建自定義組件
于是,我們就可以在自定義組件中這樣調用:
<!--文件: 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">
<!---->
<!--<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">將第一個的數(shù)據(jù)源修改為 /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,實現(xiàn)了子組件與父組件數(shù)據(jù)的雙向綁定,很簡單,是不是?
之后筆者還會對KendoUI的其他組件進行擴充,事實上,還有很多事情我們沒有做。比如,如果我們要使用kendoUI的Template功能,就可能還要做一些事情,把Template給放出來。
其實也簡單,開發(fā)出來一些預置的Template,然后要用的時候往里面丟就可以了。
后續(xù)
和 kendoDropDownList 相比,kendoGrid封裝起來可能會稍微復雜一些(主子列表、特殊標記某一列等),可能也需要舍棄一些功能,但是工作流程都是一樣的:
- 寫一個專門初始化
kendoGrid的模塊,該模塊需要根據(jù)當前的DOM對象(el)生成一個kendoGrid
- 新建一個Vue組件,引入該模塊,并初始化好
kendoGrid - ??需要注意的是,
kendoGrid需要頻繁變化數(shù)據(jù)源(比如做篩選操作的時候),所以需要用一個巧妙的方式來解決這個問題(最好不要破壞后臺的RESTFul架構)。
歡迎討論??