在 Vue2 中集成kendoDropDownList——如何在 Vue2 中集成 KendoUI

回顾


上一篇文章中,我们搭建了 KendoUI 和 Vue.js 的集成开发环境,
并且提出了一个 kendoDropDownList 的集成方案:

  1. 父组件通过 props 传递相关配置到我们包装的 component
  2. 子组件通过触发事件来进行

现在,我们可以将该方案完善一下:

  1. 父组件通过 props 传递相关配置到 我们包装的 component
  2. 通过 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 指令,必须满足:

  1. 必须接受 value 属性
  1. 组件内部需要使用 input 事件把新的值带出来

所以现在就非常简单了:

  1. 使用 Node.js express 生成一个简单的数据源
  2. 我们希望在 kendoDropDownList 组件中调用 kendoDropDownList 模块的 init 方法,传入的option应该包括:dataSource的描述(urlhttpMethod 或者直接是datavalueFieldtextField),当前的 element(this.$el),value
  3. kendoDropDownListinit 方法中添加相应的初始化方法
  4. kendoDropDownList 的值改变的时候应该触发input事件,并带上新的值
  5. 需要对组件中的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>

那么,效果应该是这样的:

kendoDropDownList最终效果

在这个例子中,我们使用了v-model,实现了子组件与父组件数据的双向绑定,很简单,是不是?

之后笔者还会对KendoUI的其他组件进行扩充,事实上,还有很多事情我们没有做。比如,如果我们要使用kendoUI的Template功能,就可能还要做一些事情,把Template给放出来。

其实也简单,开发出来一些预置的Template,然后要用的时候往里面丢就可以了。

后续


kendoDropDownList 相比,kendoGrid封装起来可能会稍微复杂一些(主子列表、特殊标记某一列等),可能也需要舍弃一些功能,但是工作流程都是一样的:

  1. 写一个专门初始化 kendoGrid 的模块,该模块需要根据当前的DOM对象(el)生成一个kendoGrid
  1. 新建一个Vue组件,引入该模块,并初始化好kendoGrid
  2. ⚠️需要注意的是,kendoGrid需要频繁变化数据源(比如做筛选操作的时候),所以需要用一个巧妙的方式来解决这个问题(最好不要破坏后台的RESTFul架构)。

欢迎讨论😁

导航:

基础环境搭建
在 Vue2 中集成kendoDropDownList

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容

  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,046评论 0 29
  • 双十一光棍节前一天,有朋友和我聊天,怨叨着这次又得独自过光棍节啦。这个时代,光棍节、圣诞节、妇女节等等所有节...
    如晓梦阅读 2,310评论 17 17
  • 明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人家?...
    珍珠贝阅读 347评论 1 1
  • 又到月底了,10月结束,意味这这一年也快结束了。回顾10月的工作与学习,收获还是挺多的。 一、个人成长 1.读书 ...
    瞌睡的猫80阅读 622评论 0 0
  • 鹿邑八景,指鹿邑的八处风景名胜,古人用《八景诗》概括,具体指太清宫隐山遗址、太清宫等。 隐隐青山爱戴烟, ...
    蒙主阅读 1,201评论 0 0