define(function (require, exports, module) { var $ = require('jquery'); var Class = require('mod/class'); var EventBase = require('mod/eventBase'); var PublicDefaults = require('mod/cascadePublicDefaults'); var AjaxCache = require('mod/ajaxCache'); //这是一个可缓存的Ajax组件 var Ajax = new AjaxCache(); /** * 有一部分option定义在PublicDefaults里面,因为CascadeItem组件不会被外部直接使用 * 外部用的是CascadeView组件,所以有一部分的option必须变成公共的,在CascadeView组件也定义一次 * 外部通过CascadeView组件传递所有的option * CascadeView内部实例化CascadeItem的时候,再把PublicDefaults内的option传递给CascadeItem */ var DEFAULTS = $.extend({}, PublicDefaults, { prevItem: undefined, // 指向前一个级联项 value: '' //初始时显示的value }); var CascadeItem = Class({ instanceMembers: { init: function ($el, options) { //通过this.base调用父类EventBase的init方法 this.base($el); this.$el = $el; this.options = this.getOptions(options); this.prevItem = this.options.prevItem; //前一个级联项 this.hasContent = false;//这个变量用来控制是否需要重新加载数据 this.cache = {};//用来缓存数据 var that = this; //代理select元素的change事件 $el.on('change', function () { that.trigger('changed.cascadeItem'); }); //当前一个级联项的值发生改变的时候,根据需要做清空和重新加载数据的处理 this.prevItem && this.prevItem.on('changed.cascadeItem', function () { //只要前一个的值发生改变并且自身有内容的时候,就得清空内容 that.hasContent && that.clear(); //如果不是第一个级联项,同时前一个级联项没有选中有效的option时,就不处理 if (that.prevItem && $.trim(that.prevItem.getValue()) == '') return; that.load(); }); var value = $.trim(this.options.value); value !== '' && this.one('render.cascadeItem', function () { //设置初始值 that.$el.val(value.split(',')); //通知后面的级联项做清空和重新加载数据的处理 that.trigger('changed.cascadeItem'); }); }, getOptions: function (options) { return $.extend({}, this.getDefaults(), options); }, getDefaults: function () { return DEFAULTS; }, clear: function () { var $el = this.$el; $el.val(''); if (this.options.keepFirstOption) { //保留第一个option $el.children().filter(':gt(0)').remove(); } else { //清空全部 $el.html(''); } //通知后面的级联项做清空和重新加载数据的处理 this.trigger('changed.cascadeItem'); this.hasContent = false;//表示内容为空 }, load: function () { var opts = this.options, paramValue, that = this, dataKey; //dataKey是在cache缓存时用的键名 //由于第一个级联项的数据是顶层数据,所以在缓存的时候用的是固定且唯一的键:root //其它级联项的数据缓存时用的键名跟前一个选择的option有关 if (!this.prevItem) { paramValue = opts.defaultParam; dataKey = 'root'; } else { paramValue = this.prevItem.getParamValue(); dataKey = paramValue; } //先看数据缓存中有没有加载过的数据,有就直接显示出来,避免Ajax if (dataKey in this.cache) { this.render(this.cache[dataKey]); } else { var params = {}; params[opts.paramName] = paramValue; Ajax.get(opts.url, params).done(function (res) { //resolveAjax这个回调用来在外部解析ajax返回的数据 //它需要返回一个data数组 var data = opts.resolveAjax(res); if (data) { that.cache[dataKey] = data; that.render(data); } }); } }, render: function (data) { var html = [], opts = this.options; data.forEach(function (item) { html.push(['<option value="', item[opts.valueField], '" data-param-value="',//将paramField对应的值存放在option的data-param-value属性上 item[opts.paramField], '">', item[opts.textField], '</option>'].join('')); }); //采用append的方式动态添加,避免影响第一个option //最后还要把value设置为空 this.$el.append(html.join('')).val(''); this.hasContent = true;//表示有内容 this.trigger('render.cascadeItem'); }, getValue: function () { return this.$el.val(); }, getParamValue: function () { return this.$el.find('option:selected').data('paramValue'); } }, extend: EventBase }); return CascadeItem; });
4. demo说明
演示代码的结构: