一、搜索Search
- 搜索框
<Search placeholder="请输入关键字" defaultValue={kw && kw != 'null' ? kw : ''} className={styles.search} onChange={() => this.handleKwChange()} onSearch={(e) => this.handleSearch(e)} />
-
引入工具方法:去掉收尾空格
import {trimStr} from '@/utils/utils'; // utils.js export function trimStr(str){ return str.replace(/(^s*)|(s*$)/g,""); }
-
搜索按钮触发搜索方法,输入内容改变自动搜索
handleSearch = e => { const { dispatch } = this.props; const { currentPage } = this.state; let kw = trimStr(e); this.setState({ keyword : kw }); dispatch({ type: 'newMallOrder/fetch', payload: { currentPage, e: { keyword: kw }, showCount: 10 }, }); }; handleKwChange = () => { const { dispatch } = this.props; const { currentPage } = this.state; if(event && event.target && event.target.value){ let value = event.target.value; this.handleSearch(value) }else{ dispatch({ type: 'newMallOrder/fetch', payload: { currentPage, e: { keyword: null }, showCount: 10 }, }); } }
二、选择器Select & TreeSelect
- 表单中嵌入Select选择器
<FormItem> {getFieldDecorator('tempTypeId',{ initialValue: 0 })( <Select placeholder="请选择" style={{ '100%' }} onChange={this.handleTempType}> <Option value={0}>H5在线编辑</Option> <Option value={1}>贺卡</Option> <Option value={2}>海报</Option> <Option value={3}>壁纸</Option> <Option value={4}>全部</Option> </Select> )} </FormItem>
选择方法:
handleTempType = value => { const { dispatch } = this.props; const { keyword } = this.state; this.setState({ tempType: tempTypeMap[value] }) dispatch({ type: 'temp/fetch', payload: { currentPage: 1, e: { keyword: keyword, subjectClass: tempTypeMap[value] }, showCount: 2 } }); dispatch({ type: 'temp/fetchType', payload: { ofClass: tempTypeMap[value] }, callback: (res) => { if(res.code == 200){ let typeList = res.data; // 获取联动选择框的数据 typeList.forEach((typeItem, index) => { dispatch({ type: 'temp/fetchThirdType', payload: typeItem.id, callback: (res) => { if(res.code == 200 && res.data.length){ typeList[index].list = res.data; } } }) }) setTimeout(() => this.setState({ typeList }), 0) } } }); }
- 联动选择的第一个选择框的父级数据
let ParentTypeData = [ { title: 'H5在线编辑', value: 0, key: 0, }, { title: '贺卡', value: 1, key: 1, }, { title: '海报', value: 2, key: 2, }, { title: '壁纸', value: 3, key: 3, }, { title: '全部', value: 4, key: 4, }, ];
- 处理获取到的联动选择第二个选择框的数据为TreeSelect需要的数据格式
let typeData = []; const typeTree = (typeList, typeData) => { if(typeList.length) { for(let i=0; i<typeList.length; i++){ typeData[i] = { title: typeList[i].kind, value: typeList[i].id, key: typeList[i].id } //二级分类 if(typeList[i].list){ typeData[i].children = []; typeTree(typeList[i].list, typeData[i].children) } } } } typeTree(typeList, typeData);
-
表单中嵌入TreeSelect选择器
<FormItem label="主题类别" {...formLayout}> <TreeSelect defaultValue={tempType == null ? 4 : tempTypeMap.indexOf(tempType)} value={parentTypeId} style={{display: `${editDisable ? 'none' : 'inline-block'}`, '47%', marginRight: '6%'}} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} treeData={ParentTypeData} placeholder="请选择" onChange={handleParentType} /> {form.getFieldDecorator('typeIds', { rules: [{ type:"array", required: true, message: '请选择主题类别'}], initialValue: detail.types && detail.types.length ? detail.types.map((type) => type.id) : [] })( <TreeSelect multiple // 多选 style={{ `${editDisable ? '100%' : '47%'}`}} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} treeData={typeData} placeholder="请选择" disabled={editDisable} onChange={handleTypeChange} /> )} </FormItem>
三、图片视频音频上传Upload
- 弹框表单中上传一张图片、一个音频
- 引入upload.js中封装的handImageUpload文件上传七牛云的方法
import { handleImageUpload } from '@/utils/upload'; // 预览文件时url前面需要加七牛云服务器前缀 // eg: 'http://fileserver.liuliu123.cn/' import { setFileHost } from '@/utils/utils';
upload.js
var qiniu = require('qiniu-js') import axios from 'axios'; import configs from '@/utils/env' import { message } from 'antd'; //七牛云上传,input, onchange事件 export function handleImageUpload(file, type, resName) { // console.log(file,'handleImageUpload') let suffix = file.type.split('/')[1]; return new Promise(function(resolve, reject){ if(!file) { reject('file is undefined') } function dataURItoBlob(base64Data) { var byteString; if(base64Data.split(',')[0].indexOf('base64') >= 0) byteString = atob(base64Data.split(',')[1]); else byteString = unescape(base64Data.split(',')[1]); var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0]; var ia = new Uint8Array(byteString.length); for(var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ia], { type: mimeString }); } function randomString(len) { len = len || 32; var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; var maxPos = $chars.length; var pwd = ''; for (let i = 0; i < len; i++) { pwd += $chars.charAt(Math.floor(Math.random() * maxPos)); } return pwd; } var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(e) { var fileBlob = dataURItoBlob(e.target.result); var key; switch(type){ case 'audio': key = 'sys/file/music/' + resName + '.' + suffix; break; case 'video': key = 'liveWallPaper/' + resName + '.' + suffix; break; case 'tutorial': //教程文件 key = 'sys/tutorial/' + new Date().getTime() + randomString(5) + '.' + suffix; break; case 'tutorialVideo': //针对IOS富文本视频显示问题单独处理教程视频 key = 'yihezo/' + new Date().getTime() +randomString(5) + '.' + suffix; break; default: key = 'user/h5/' + new Date().getTime() +randomString(5) + '.' + suffix; } var putExtra = { fname: file.name, params: {}, mimeType: ["image/png", "image/jpeg", "image/jpg", "image/gif", "image/webp", "image/apng", "image/svg", "audio/mp3", "audio/mp4", "audio/ogg", "audio/mpeg", "video/mp4", "video/ogg", "video/webm"] }; var config = { useCdnDomain: true, }; if(type == 'tutorialVideo' ){ //针对IOS富文本视频显示问题单独处理教程视频 axios.post(configs[process.env.API_ENV]['BG_SERVER']+'/file/qiniu/token/video', { key: 'yihezo/' + new Date().getTime() +randomString(5) //入参:教程视频的key }, { headers: { AuthorizationToken: localStorage.getItem('login_token') } }).then(res =>{ let {data} = res; if(data.code == 200) { let token = data.data.token; let observable = qiniu.upload(fileBlob, key, token, putExtra, config) let subscription = observable.subscribe({next(res){ // console.log(res, 'loading') }, error(res){ message.error('上传失败'); }, complete(res) { resolve(res.key) }}) //subscription.unsubscribe() // 上传取消 } else { message.error('获取七牛云token失败'); } }).catch(error => { console.error(error) reject(error) }) }else{ axios.post(configs[process.env.API_ENV]['BG_SERVER']+'/file/qiniu/token', {}, { headers: { AuthorizationToken: localStorage.getItem('login_token') } }).then(res =>{ let {data} = res; if(data.code == 200) { let token = data.data.token; let observable = qiniu.upload(fileBlob, key, token, putExtra, config) let subscription = observable.subscribe({next(res){ // console.log(res, 'loading') }, error(res){ message.error('上传失败'); }, complete(res) { resolve(res.key) }}) //subscription.unsubscribe() // 上传取消 } else { message.error('获取七牛云token失败'); } }).catch(error => { console.error(error) reject(error) }) } } }) }
- state中定义初始值
fileThumb: null, // 存储上传七牛云后返回的图片url fileUri: null, // 存储上传七牛云后返回的文件url fileVisible: false, // 控制预览文件的弹框是否visible previewVisible: false,// 控制预览图片的弹框是否visible previewImage: '', //预览要上传的图片和上传后的图片的url previewFile: '' //预览要上传的图片和上传后的图片的url
-
弹框表单中Upload组件
// 上传按钮 const ImgUpButton = ( <div> <Icon type="plus" /> <div className="ant-upload-text">Upload</div> </div> ); const FileUpButton = ( <Button> <Icon type="upload" /> Upload </Button> )
<FormItem label="资源图片" {...this.formLayout}> { getFieldDecorator('thumb', { rules: [{ required: true, message: '请上传图片' }], initialValue: current.thumb ? [{ // 默认必须是数组 uid: '-1', status: 'done', name: current.resName, url: `${setFileHost()+current.thumb}`, thumbUrl: `${setFileHost()+current.thumb}` }] : "" // 无值时必须是空串 })( <div> <Upload accept="image/*" // 限制上传的文件类型 action={(file) => handleImageUpload(file, 'image').then(res => { const newFileThumb = []; newFileThumb.push(res); this.setState({ fileThumb: newFileThumb, }) })} // 上传七牛云后存储url listType="picture-card" fileList={imgList} // 显示的图片数组 onRemove={this.handleImgRemove} onPreview={this.handleImgPreview} onChange={this.handleImgChange} > {imgList.length >= 1 ? null : ImgUpButton} </Upload> <Modal visible={previewVisible} footer={null} onCancel={this.handleImgCancel}> <img alt="资源图片" style={{ '100%' }} src={previewImage} /> </Modal> </div> )} </FormItem> <FormItem label="资源文件" extra={resNameError || resName == null ? <span style={{color:'#1890FF'}}>请先输入资源名称</span> : ''} {...this.formLayout}> {getFieldDecorator('uri', { rules: [{ required: true, message: '请上传文件' }], initialValue: current.uri ? [{ uid: '-1', status: 'done', name: current.uri, url: `${setFileHost()+current.uri}` }] : "" })( <div> <Upload accept="audio/mp3, audio/mp4, audio/ogg, audio/mpeg" disabled={ resNameError || resName == null ? true : false } action={(file) => handleImageUpload(file, 'audio', resName).then(res => { const newFileUri = []; newFileUri.push(res); this.setState({ fileUri: newFileUri }) })} fileList={fileList} onRemove={this.handleFileRemove} onPreview={this.handleFilePreview} onChange={this.handleFileChange} > {fileList.length >= 1 ? null : FileUpButton} </Upload> <Modal visible={fileVisible} footer={null} onCancel={this.handleFileCancel} style={{textAlign: 'center'}}> <audio src={previewFile} style={{ '80%' }} controls="controls" autoPlay="autoplay"> 您的浏览器不支持 audio 标签。 </audio> </Modal> </div> )} </FormItem>
// 上传图片 使用的方法 // 删除、预览弹框关闭、预览图片url和预览弹框打开,存储改变的图片url handleImgRemove = () => { this.setState({ imgList: [], fileThumb: [''], }) return true } handleImgCancel = () => this.setState({ previewVisible: false }) handleImgPreview = (file) => { this.setState({ previewImage: file.url || file.thumbUrl, previewVisible: true, }); } handleImgChange = ({ fileList }) => this.setState({ imgList: fileList }) // 上传文件 使用的方法 // 删除、预览弹框关闭、预览文件url和预览弹框打开,存储文件的图片url handleFileRemove = () => { this.setState({ fileList: [], fileUri: [''], }) return true } handleFileCancel = () => this.setState({ fileVisible: false }) handleFilePreview = (file) => { file.url ? this.setState({ previewFile: file.url, fileVisible: true, }) : message.error('请先保存'); } handleFileChange = ({ fileList }) => this.setState({ fileList })
-
弹框表单中上传多张图片
-
引入upload.js中封装的handImageUpload文件上传七牛云的方法
import { handleImageUpload } from '@/utils/upload'; import {setFileHost} from '@/utils/utils';
- state中定义初始数据
// 上传多张轮播图(可上传视频) imgList: [], fileThumbs: [], previewVisible: false, previewImage: '', // 上传一张图片 introImgList: [], introFileThumb: '', introPreviewVisible: false, introPreviewImage: '',
-
showModal显示弹框的方法中: 处理获得的图片数组存入state
showEditModal = item => { const { dispatch } = this.props; dispatch({ type: 'project/fetchDetail', payload: { goodsId: item.id }, callback: (res) => { if(res){ this.setState({ detail: res.data, imgList: res.data.rotationChart && res.data.rotationChart.length ? this.initImgList(res.data) : "", // Upload显示图片本地存储的图片url数组 fileThumbs: res.data.rotationChart && res.data.rotationChart.length ? this.initFileThumbs(res.data) : "", // 上传七牛云后存储的用于传给后端的图片url数组 introImgList: res.data.introPic ? [{ uid: '-1', status: 'done', name: res.data.introPic, url: `${setFileHost()+res.data.introPic}`, thumbUrl: `${setFileHost()+res.data.introPic}` }] : '', introFileThumb: res.data.introPic ? res.data.introPic : '', current: item, addSubmit: false }, () => { this.setState({ visible: true }) }); } } }) };
-
弹框表单中嵌入Upload组件
const ImgUpButton = ( // 上传图片的按钮 <div> <Icon type="plus" /> <div className="ant-upload-text">Upload</div> </div> );
<FormItem label="产品图片" {...formLayout}> { getFieldDecorator('rotationChart', { rules: [{ required: true, message: '请上传1-7张图片'}], // 默认显示是图片数组,无值也是空数组 initialValue: current && detail && detail.rotationChart && detail.rotationChart.length ? initImgList(detail) : [] })( <div> <Upload accept="image/*" // action={(file) => handleImageUpload(file, 'image').then(res => { // handleFileThumb(res, file, imgList) // })} listType="picture-card" fileList={imgList} onPreview={handleImgPreview} onRemove={handleImgRemove} // beforeUpload上传前的处理函数: 嵌套handleImageUpload方法 (上传一张图片或一个文件时,如果需要上传前判断文件类型、文件大小也是这么做) // 1.包含handleFileThumb方法,代替action实现上传七牛云服务器后存储state;2.同时将新的图片数组imgArray存入本地imgList改变Upload组件显示的图片 beforeUpload={beforeUpload} // onChange={handleImgChange} > {imgList.length >= 7 ? null : ImgUpButton} </Upload> <Modal visible={previewVisible} footer={null} onCancel={handleImgCancel} style={{textAlign: 'center'}}> { previewType == 'liveWallPaper' ? <video src={previewImage} style={{ '50%' }} controls="controls" autoPlay="autoplay"> 您的浏览器不支持 video 标签。 </video> : <img alt="产品图片" style={{ '100%' }} src={previewImage} />} </Modal> </div> )} </FormItem>
-
使用到的方法
initImgList = (item) => { // 处理Upload默认显示的数据 let defaultImgList = []; item.rotationChart.forEach((imgListItem, index) => { defaultImgList.push ({ uid: `${-1-index}`, status: 'done', name: item.name, url: imgListItem.img ? `${setFileHost()+imgListItem.img}` : '', thumbUrl: imgListItem.thumb ? `${setFileHost()+imgListItem.thumb}` : '' }) }) return defaultImgList }
initFileThumbs = (item) => { // 不更改不上传新的图片时默认向后端传的图片url数组 let defaultFileThumbs = []; item.rotationChart.forEach((fileThumb, index) => { defaultFileThumbs[index] = fileThumb; }) return defaultFileThumbs }
handleFileThumb = (res, file, imgList) => { // 更改fileThumbs数组 let { fileThumbs } = this.state; fileThumbs[imgList.length-1] = { img: res, index: imgList.length-1, type: file.type.split('/')[0], thumb: res }; this.setState({ fileThumbs }) }
// 关闭预览弹框 handleImgCancel = () => this.setState({ previewVisible: false }) // 显示预览弹框 handleImgPreview = (file) => { this.setState({ previewImage: file.url || file.thumbUrl, previewVisible: true, }); } // 删除预览弹框 handleImgRemove = (file) => { const { fileThumbs, imgList } = this.state; let newList = [...imgList]; let newFileThumbs = [...fileThumbs]; newList.forEach((imgItem, index) => { if(imgItem.uid == file.uid){ newList.splice(index, 1) newFileThumbs.splice(index, 1) } }) this.setState({ imgList: newList, fileThumbs: newFileThumbs }, () => { return true }) }
beforeUpload = (file) => { let type = file.type.split('/')[0]; let name = file.name.split('.')[0]; // 判断文件类型 -- 如果是视频url直接存入imgList,存入fileThumb if(type == 'video') { let imgArray = [...this.state.imgList]; imgArray.push(file); handleImageUpload(file, 'video', name).then(res => { this.setState({ imgList: imgArray }) this.handleFileThumb(res, file, imgArray) }) }else{ // 如果是图片,使用react-cropper插件相关设置进行裁剪处理 // 当打开同一张图片的时候清除上一次的缓存 if (this.refs.cropper) { this.refs.cropper.reset(); } var reader = new FileReader(); const image = new Image(); //因为读取文件需要时间,所以要在回调函数中使用读取的结果 reader.readAsDataURL(file); //开始读取文件 reader.onload = (e) => { image.src = reader.result; image.onload = () => { this.setState({ srcCropper: e.target.result, //cropper的图片路径 selectImgName: file.name, //文件名称 selectImgSize: (file.size / 1024 / 1024), //文件大小 selectImgSuffix: file.type.split("/")[1], //文件类型 editImageModalVisible: true, //打开控制裁剪弹窗的变量,为true即弹窗 }) if (this.refs.cropper) { this.refs.cropper.replace(e.target.result); } } } return false; } }
-
不需要裁剪的使用beforeUpload判断文件大小的上传一张图片
<FormItem label="人物介绍图片" {...formLayout}> {getFieldDecorator('introPic', { initialValue: current && detail && detail.introPic ? [{ uid: '-1', status: 'done', name: detail.introPic, url: `${setFileHost()+detail.introPic}`, thumbUrl: `${setFileHost()+detail.introPic}` }] : '' })( <div> <Upload accept="image/*" // action={(file) => handleImageUpload(file, 'image').then(res => { // handleIntroFileThumb(res) // })} listType="picture-card" fileList={introImgList} onPreview={handleIntroImgPreview} onRemove={handleIntroImgRemove} beforeUpload={beforeIntroUpload} // onChange={handleIntroImgChange} > {introImgList.length >= 1 ? null : ImgUpButton} </Upload> <Modal visible={introPreviewVisible} footer={null} onCancel={handleIntroImgCancel} style={{textAlign: 'center'}}> <img alt="人物介绍图片" style={{ '100%' }} src={introPreviewImage} /> </Modal> </div> )} </FormItem>
beforeIntroUpload = (file) => { const isLt3M = file.size / 1024 / 1024 < 3; if (!isLt3M) { //添加文件限制 message.error('文件大小不能超过3M'); return false; } // console.log('file', file) handleImageUpload(file, 'image').then(res => { this.setState({ // 存入introImgList introImgList: [{ uid: file.uid, status: 'done', name: file.name, url: `${setFileHost()+res}`, thumbUrl: `${setFileHost()+res}` }] }) this.handleIntroFileThumb(res) // 存入introFileThumbs }) return true }
转载请注明出处