最近真是忙啊忙,而且在用我最讨厌的extjs写东西···
然而实在是忙得没精力做别的了,所以发一篇extjs相关的内容。
总体来说extjs是一个不错的框架,用来做XX系统什么的非常的般配,只不过我讨厌他的编程方式,虽然很灵活,很MVC,但是这一切都要建立在你妥协在他的规则之下。
他灵活是因为每一个空间的文档,属性加事件加方法足有几百多个,总会有一个你会用到······
开始我们的扩展之前,先说一个小tip,当你用的是extjs5,而且用的是chrome浏览器的时候,你会发现你的表单空间点击之后会串行,像这样:
然后因为他的input包在一个display是table-cell的div里,当然这个div的父元素的display是table。这其实很正常,因为我们需要做组合的空间的时候能保证横向的延展,boot也是这么做的。但是我们会发现chrome审查元素的时候会发现奇怪的东西,比如···
他的div有一个默认的 vertical-align-- baseline···,天晓得为什么属性的默认值也会出事,我也没进一步的去调试,因为解决办法是有的,
我们可以暴力一点,加个:
- div{vertical-align:top}
即可,感觉太暴力的小朋友可以只改那个样式的vertical-align。改好的样子就很正常了:
然后我们继续说扩展一个插件这回事儿,我要做的事情是这样的。
需要一个上面第一张图里面的那种上传图片的空间,上传上去后能够同步显示,当然这需要先上传到服务器,然后返回地址,可以删除,可以新增,然而这些都是次要的。
邪恶主管说我传给你用来绑定的字段值是一个有id有url的json串,但是你返回给我的需要时一个都好分割的id数组·······
我的表单已经抽成公共的了,我不希望为了它在提交前作一些额外的转换,所以重点是,我需要他绑定值得时候像正常的控件那样,而我获取值得时候,也要不经过额外的处理···
算了不首先了···extjs这么恶心的东西估计用的人也不多,直接先把v层的代码贴出来吧···
- /**
- *
- * TODO 用于多组图片上传
- * 组件正常接收 form组件 value值 类型为json结构的字符串
- * 输出value值为 以”,“分割的id字符串,表单提交时不必特殊考虑.
- *
- */
- Ext.define('Backend.plugin.tmImgField.TmImgField', {
- extend: 'Ext.Container',
- layout: {
- type: 'hbox',
- bodyPadding: 10
- },
- requires: [
- 'Ext.Img',
- "Backend.plugin.tmImgField.TmImageUploadController"
- ],
- controller: 'imageUpload',
- xtype: 'tmImgfield',
- bodyPadding: 10,
- margin:'0 3 5 0',
- frame: true,
- align: 'middle',
- autoDestroy: true,
- bodyPadding: 15,
- width: '100%',
- baseImg: '/static/css/images/addImg.jpg',
- buttonText:'上传',
- initComponent: function () {
- var self = this,
- baseImg = self.baseImg;
- var label = self.fieldLabel,
- name = self.name,
- value = self.value || '',
- allowBlank = self.allowBlank;
- //label
- var items = [];
- items.push({
- html:'<span style="color:#666;">'+label+':</span>',
- width:90,
- style:'text-align:right;',
- });
- //form hidden field
- var hiddenField = Ext.create("Ext.form.field.Text", {
- name: name,
- value: value,
- allowBlank: allowBlank,
- hidden: true,
- listeners: {
- setImgValues:'changeValue',
- change: 'checkValue',
- validitychange: 'validitychange'
- },
- reference: 'imgInput',
- });
- items.push(hiddenField);
- //添加按钮
- var imgBtn = Ext.create('Ext.form.FieldSet',{
- layout:'vbox',
- cls:'imgFieldSet',
- reference:'imgFieldBtn',
- style:{border:0},
- padding:4,
- width:108,
- height:137,
- items: [
- {
- xtype:'image',
- autoEl: 'div',
- imgCls: 'product_image',
- width:100,
- height:100,
- src:baseImg
- },{
- xtype:'button',
- text:self.buttonText,
- width:80,
- margin:'5 0 0 10',
- handler: 'addImg'
- }
- ]
- });
- //右侧展示区域
- var field = Ext.create('Ext.form.FieldSet',{
- padding:'4',
- margin:'0 5',
- flex:1,
- reference: 'imgArea'
- });
- field.add(imgBtn);
- items.push(field);
- self.items = items;
- self.callParent();
- },
- afterRender: function () {
- var self = this;
- self.callParent(arguments);
- }
- });
现在我们开始首先,
首先你需要一个form控件去接受值,我们选择用text而不是hidden,因为我们需要allowBlank方法控制是否必填,而hidden没有这个属性(详情请看hidden那n多个属性),然后把这个text隐藏起来,因为我们可见的东西是那些img。
然后我们要先收到传过来的值,这里面有两个办法,最好的办法是override这个text的setValue方法,然而我们用的是另外一种,别问为什么,我脑子短路当时。
我们给这个text三个监听,我们先讲第一个,change。
顾名思义,就是值发生变化的事后启动。当然也包括setValue的时候。
- //校验value
- checkValue: function (item, value) {
- if(!value){ item.fireEvent('setImgValues',{},'delAll'); return;}
- try{
- var _value = Ext.JSON.decode(value);
- if(typeof(_value) === 'object')
- item.fireEvent('setImgValues',_value,'add');
- }catch(e){
- }
- },
就是查看value,然后判断,如果是object那就手动启动另外一个监听,如果是正常值,就什么也不做。
然后我们就会跳到另外一个监听里,
- //值修改事件
- changeValue: function (value,flag) {
- if(!value) return;
- var maxLength = this.getView().maxLength || 0,
- imgFieldBtn = this.lookupReference('imgFieldBtn');
- var items = this.imgValues || [];
- if(flag === 'add'){
- items = Ext.Array.union(items, value);
- }else if(flag==='del'){
- delete items[value]
- }else if(flag==='delAll'){
- items = [];
- }
- var imgArea = this.lookupReference('imgArea'),
- oldItems = imgArea.items.items;
- //先删除
- for(var i = oldItems.length- 1; i > -1; i --){
- if(oldItems[i].imgType && oldItems[i].imgType=='imgBox'){
- oldItems[i].destroy();
- }
- }
- //input value
- var inputValue = [];
- //重新渲染
- for(var key in items ){
- var item = items[key];
- var imgBox = this.buildImg(key,item);
- imgArea.insert(imgArea.items.getCount()-1,imgBox);
- inputValue.push(item.id);
- }
- //赋值
- this.imgValues = items;
- this.lookupReference('imgInput').setValue(inputValue.join(','));
- if(maxLength && maxLength <= inputValue.length){
- imgFieldBtn.hide();
- }else{
- imgFieldBtn.show();
- }
- },
他把显示的图片删除再重构,我们把得到的json放在this里即可,然后显示的value值我们付成逗号分隔的字符串。每次的删除,增加操作我们都手动的出发这个方法即可。
我们还人性化的给加了maxLength,如果到了最大值,就把增加按钮隐藏。
这样input值得绑定和获取就能按照正常的extjs的表单控件走了。
最后一个问题,校验是否必填。像这样
这是extjs自带的功能,但是我们的input控件已经隐藏了,那个边是我们自己画的·······怎么办。
没关系,我们在他的文档里找啊找找啊找,就找到了第三个监听,validitychange。
这个属性监听validity状态的改变···也是醉了··· 这也给接口········
- // validate 改变
- validitychange: function(field,isValid,eOpts){
- var self = this,
- fieldSet = this.lookupReference('imgArea');
- if(isValid){
- fieldSet.removeCls('field-error');
- }else{
- fieldSet.addCls('field-error');
- }
- },
我们监听它的值,然后给我们的边框加一个class,这个class自然是改border-color的啦。
这样,一切就ok,他和普通的控件一样用,因为他的setValue和getValue传递的都是符合我们要求的值。而且可以做校验,可以设定上传数量。