在 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

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