├── .editorconfig ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── babel.config.js ├── example ├── App.vue ├── CustomRate.vue ├── CustomSlider.vue └── main.js ├── package-lock.json ├── package.json ├── public ├── example.gif ├── favicon.ico ├── img │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ └── 5.png └── index.html ├── src ├── EleEditable.vue ├── EleEditableMixin.js ├── EleEditableWrapper.vue ├── components │ ├── EleCommonTime.vue │ ├── EleEditableCheckbox.vue │ ├── EleEditableColor.vue │ ├── EleEditableDate.vue │ ├── EleEditableDateText.vue │ ├── EleEditableDatetime.vue │ ├── EleEditableDatetimeText.vue │ ├── EleEditableImage.vue │ ├── EleEditableInput.vue │ ├── EleEditableNumber.vue │ ├── EleEditableRadio.vue │ ├── EleEditableSelect.vue │ ├── EleEditableStatus.vue │ ├── EleEditableSwitch.vue │ ├── EleEditableText.vue │ ├── EleEditableTextarea.vue │ ├── EleEditableTime.vue │ ├── EleEditableTimeText.vue │ ├── EleEditableUploadImage.vue │ └── EleEditableUrl.vue ├── index.js └── wrapper │ ├── EleEditableWrapperDisplay.vue │ └── EleEditableWrapperForm.vue └── vue.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tests 3 | docs 4 | documentation 5 | public 6 | vue.config.js 7 | coverage 8 | example 9 | jest.config.js 10 | .eslintrc.js 11 | cypress.json 12 | .browserslistrc 13 | postcss.config.js 14 | babel.config.js 15 | .editorconfig 16 | .cypress.json 17 | .vscode 18 | .env.docs 19 | dist/demo.html 20 | .env.dev-doc 21 | .env.dev-example -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 二当家的 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-ele-editable | 高效、简单、强大的 element-ui 行内编辑组件 2 | 3 | [![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg)](https://opensource.org/licenses/mit-license.php) 4 | [![npm](https://img.shields.io/npm/v/vue-ele-editable.svg)](https://www.npmjs.com/package/vue-ele-editable) 5 | [![download](https://img.shields.io/npm/dw/vue-ele-editable.svg)](https://npmcharts.com/compare/vue-ele-editable?minimal=true) 6 | 7 | ## 介绍 8 | 9 | vue-ele-editable 是一个高效、简单、强大的 element-ui 行内编辑组件, 引用组件后, 仅通过数据就可以完成行内编辑功能, 具体特点如下: 10 | 11 | - 支持多种内置组件: input、select、radio、checkbox、textarea、date、time、datetime、text、url、status、switch、image、upload-image、time-text、date-text、datetime-text、color、number 12 | - 支持 Popover 和 Inline 两种模式 13 | - 支持数据校检、自定义属性、自定义显示数据、自定义发送数据 14 | - 足够简单, 仅需要 1 行 html 代码和数据即可 15 | 16 | > 为了帮助您更好的了解和使用, star 数超过 100 的话, 有视频源码讲解, 希望能给个 star😘😘😘 17 | 18 | ## 效果图 19 | 20 | [![示例](./public/example.gif)](https://codepen.io/dream2023/pen/dBNNbP) 21 | 22 | ## 在线示例 23 | 24 | [https://codepen.io/dream2023/pen/dBNNbP](https://codepen.io/dream2023/pen/dBNNbP) 25 | 26 | ## 安装 27 | 28 | ```bash 29 | npm install vue-ele-editable --save 30 | ``` 31 | 32 | ## 使用 33 | 34 | ```js 35 | import EleEditable from 'vue-ele-editable' 36 | Vue.use(EleEditable) 37 | 38 | // 在引入 EleEditable 时,可以传入一个全局配置对象 39 | // key 是组件名, value 是组件的属性, 例如: 40 | Vue.use(EleEditable, { 41 | // 所有 image 类型的组件都会有 lazy: true 的属性 42 | image: { 43 | lazy: true 44 | }, 45 | // 所有的 number 类型的组件都会有 step: 10 的属性 46 | number: { 47 | step: 10 48 | }, 49 | ... 50 | }) 51 | ``` 52 | 53 | ## Props 54 | 55 | ### 参数总览 56 | 57 | ```js 58 | props: { 59 | // 类型 60 | type: { 61 | type: String, 62 | default: 'text' 63 | }, 64 | // 字段 65 | field: { 66 | type: String, 67 | required: true 68 | }, 69 | // 是否为行内 70 | inline: { 71 | type: Boolean, 72 | default: false 73 | }, 74 | // 标题 75 | title: String, 76 | // 字段值 77 | value: [String, Number, Boolean, Array, Date], 78 | // 默认值 79 | defaultValue: { 80 | type: [String, Number, Boolean, Array, Date], 81 | default: null 82 | }, 83 | // 自定义组件是否需要包裹 84 | isNoWrapper: { 85 | type: Boolean, 86 | default: false 87 | }, 88 | // 选项 89 | options: { 90 | type: Array, 91 | default () { 92 | return [] 93 | } 94 | }, 95 | // 请求地址 96 | requestFn: Function, 97 | // 校检规则 98 | rules: [Array, Object], 99 | // 其他附带数据 100 | customData: Object, 101 | // 自定义属性 102 | customAttrs: Object, 103 | // 格式化显示数据 104 | displayFormatter: Function, 105 | // 对请求数据格式化 106 | valueFormatter: Function, 107 | // 值空时显示的文本 108 | emptyText: { 109 | type: String, 110 | default: '空' 111 | } 112 | } 113 | ``` 114 | 115 | ### 参数讲解 116 | 117 | #### type: 118 | 119 | `type` 用于指定渲染组件, 目前支持的内置组件有: 120 | 121 | | 类型 | 含义 | 属性参考 | 122 | | ------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------- | 123 | | text | 静态文本 | | 124 | | image | 单个图片/多张图片 | [vue-ele-gallery](https://github.com/dream2023/vue-ele-gallery) | 125 | | upload-image | 上传图片 | [vue-ele-upload-image](https://github.com/dream2023/vue-ele-upload-image) | 126 | | input | 可编辑的单行文本 | [element-ui input](https://element.eleme.cn/#/zh-CN/component/input) | 127 | | textarea | 可编辑的多行文本 | [element-ui input](https://element.eleme.cn/#/zh-CN/component/input) | 128 | | select | 下拉框 | [element-ui select](https://element.eleme.cn/#/zh-CN/component/select) | 129 | | number | 可编辑数字 | [element-ui input-number](https://element.eleme.cn/#/zh-CN/component/input-number) | 130 | | radio | 单选 | [element-ui radio](https://element.eleme.cn/#/zh-CN/component/radio) | 131 | | checkbox | 多选 | [element-ui checkbox](https://element.eleme.cn/#/zh-CN/component/checkbox) | 132 | | datetime | 可编辑的日期时间 (可接受时间戳, 字符串, Date 类型值) | [element-ui datetime-picker](https://element.eleme.cn/#/zh-CN/component/datetime-picker) | 133 | | datetime-text | 不可编辑的日期时间 (接受值同上) | | 134 | | date | 可编辑的日期 (接受值同上) | [element-ui date-picker](https://element.eleme.cn/#/zh-CN/component/date-picker) | 135 | | date-text | 不可编辑的日期 (接受值同上) | | 136 | | time | 可编辑的时间 (接受值同上) | [element-ui time-picker](https://element.eleme.cn/#/zh-CN/component/time-picker) | 137 | | time-text | 不可编辑的时间 (接受值同上) | | 138 | | status | 状态 | [element-ui tag](https://element.eleme.cn/#/zh-CN/component/tag) | 139 | | switch | 开关 | [element-ui switch](https://element.eleme.cn/#/zh-CN/component/switch) | 140 | | url | 链接 | | 141 | | color | 颜色 | [element-ui color-picker](https://element.eleme.cn/#/zh-CN/component/color-picker) | 142 | 143 | 当`type`不是以上任何一个类型时, 就会按照传递的名字渲染, 可以进行自定义扩展组件, 具体参考 [自定义扩展示例 rate](./example/CustomRate.vue), [自定义扩展示例 slider](./example/CustomSlider.vue), 具体表现形式, 请看[在线示例](https://codepen.io/dream2023/pen/dBNNbP) 144 | 145 | ### isNoWrapper: 146 | 147 | `isNoWrapper`用于自定义组件是否需要包裹, 举例, input 是包裹组件, switch 就是不包裹组件, 内置组件的包裹与否无法改变, 只能改变自定义组件, 例如上面的 `rate` 组件就是不包裹, `slider`组件就是包裹组件 148 | 149 | ### customAttrs: 150 | 151 | `customAttrs` 自定义组件属性, 例如将 input 变为密码框: 152 | 153 | ```js 154 | { 155 | type: 'input', 156 | // 属性参考 element-ui input组件 157 | customAttrs: { 158 | 'show-password': true 159 | } 160 | } 161 | ``` 162 | 163 | ### field: 164 | 165 | `field` 用于发送请求, 作为数据的 `key`, 例如: 166 | 167 | ```js 168 | { 169 | value: 'zhang' 170 | field: 'name' 171 | } 172 | 173 | // 最终发送的数据为: 174 | { 175 | name: 'zhang' 176 | } 177 | ``` 178 | 179 | ### inline: 180 | 181 | `inline` 用于指定是采用 `popover` 还是 `inline` 的模式, 默认为 `popover` 182 | 183 | ### title: 184 | 185 | `title` 用于弹窗的标题 186 | 187 | ### value: 188 | 189 | `value` 值, 可用 `v-model` 绑定 190 | 191 | ### defaultValue: 192 | 193 | `defaultValue` 当 `value` 不存在时, 代替 `value`, 例如: 194 | 195 | ```js 196 | { 197 | value: '', 198 | field: 'name', 199 | defaultValue: '匿名' 200 | } 201 | 202 | // 最终显示到屏幕上为: 匿名 203 | ``` 204 | 205 | ### displayFormatter: 206 | 207 | `displayFormatter` 用于对值显示的进一步处理, 例如: 208 | 209 | ```js 210 | // 伪代码 211 | { 212 | value: 10, 213 | displayFormatter: function (value) { 214 | return `${value} 岁` 215 | } 216 | } 217 | 218 | // 最终显示到屏幕上为: 10 岁 219 | ``` 220 | 221 | ### emptyText: 222 | 223 | `emptyText` 用于当无数据时, 显示的字符串, 例如: 224 | 225 | ```js 226 | { 227 | field: 'mobile', 228 | // 当 value, defaultValue 和 displayFormatter都返回空时, 才起作用 229 | value: '', 230 | defaultValue: '', 231 | displayFormatter: null, 232 | emptyText: '无手机可用' 233 | } 234 | 235 | // 最终显示到屏幕上为: 无手机可用 236 | ``` 237 | 238 | ### options: 239 | 240 | `options` 用于 checkbox、radio、select、status 组件的选项, 支持对象数组和字符串数组: 241 | 242 | ```js 243 | // 对象数组形式 (text 用于展示, 实际值是 value) 244 | options: [{ text: '男', value: 'male' }, { text: '女', value: 'female' }] 245 | 246 | // 字符串数组 (相当于 [{ text: '男', value: '男' }, { text: '女', value: '女' }]) 247 | options: ['男', '女'] 248 | ``` 249 | 250 | ### requestFn: 251 | 252 | `requestFn` 请求函数, 此函数无论如何最终要返回一个 `Promise` 示例, 用于判断请求的状态和结果 253 | 254 | 有两种情况, 一种是你需要对原请求的响应结果进行处理, 可以套一层 Promise: 255 | 256 | ```js 257 | // 伪代码 258 | async function requestFn(data) { 259 | return new Promise((resolve, reject) => { 260 | try { 261 | const res = await axios.post('/post', data) 262 | // 对res做各种处理 263 | ... 264 | resolve() 265 | } catch(e) { 266 | reject(e) 267 | } 268 | }) 269 | } 270 | ``` 271 | 272 | 另一个种是不需要处理, 可以直接返回一个`Promise`对象 273 | 274 | ```js 275 | async function requestFn(data) { 276 | return axios.post('/post', data) 277 | } 278 | ``` 279 | 280 | ### rules: 281 | 282 | `rules` 用于校检, 校检规则同 element-ui 的 form 一样, 都是使用的 [async-validator](https://github.com/yiminghe/async-validator), 支持数组和对象两种形式, 例如: 283 | 284 | ```js 285 | // 对象 286 | rules: { 287 | required: true, 288 | message: '名称不能为空' 289 | } 290 | 291 | // 数组 292 | rules: [ 293 | { type: 'number', message: '年龄必须填写数字' }, 294 | { required: true, message: '年龄必填填写' } 295 | ] 296 | ``` 297 | 298 | ### customData: 299 | 300 | `customData` 用于携带额外数据, 例如: 301 | 302 | ```js 303 | // 伪代码 304 | 305 | // props的值 306 | { 307 | field: 'name', 308 | value: 'zhangchaojie', 309 | customData: { 310 | id: 10, 311 | status: 1 312 | } 313 | } 314 | 315 | // 最终发送的数据为: 316 | { 317 | name: 'zhangchaojie', 318 | id: 10, 319 | status: 1 320 | } 321 | ``` 322 | 323 | ### valueFormatter: 324 | 325 | `valueFormatter` 用于对请求数据的进一步处理, 例如: 326 | 327 | ```js 328 | // 伪代码 329 | 330 | // props 值 331 | field: 'age', 332 | value: 10, 333 | customData: { id: 1 }, 334 | valueFormatter: function (value) { 335 | return value + 1 336 | } 337 | 338 | // 最终发送的值为: 339 | { 340 | age: 11, 341 | id: 1 342 | } 343 | ``` 344 | 345 | ## 参考链接 346 | 347 | - [x-editable](http://vitalets.github.io/x-editable) 348 | - [element-ui](http://element-cn.eleme.io) 349 | - [dolphinphp](https://www.kancloud.cn/ming5112/dolphinphp/256299) 350 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 94 | 95 | 500 | -------------------------------------------------------------------------------- /example/CustomRate.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | -------------------------------------------------------------------------------- /example/CustomSlider.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | -------------------------------------------------------------------------------- /example/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import EleEditable from '../src/index' 4 | import ElementUI from 'element-ui' 5 | import 'element-ui/lib/theme-chalk/index.css' 6 | import CustomRate from './CustomRate' 7 | import CustomSlider from './CustomSlider' 8 | Vue.component(CustomRate.name, CustomRate) 9 | Vue.component(CustomSlider.name, CustomSlider) 10 | 11 | Vue.use(ElementUI) 12 | Vue.use(EleEditable, { 13 | image: { 14 | lazy: true 15 | }, 16 | number: { 17 | step: 10 18 | } 19 | }) 20 | Vue.config.productionTip = false 21 | 22 | new Vue({ 23 | render: h => h(App) 24 | }).$mount('#app') 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-ele-editable", 3 | "description": "高效、简单、强大的 element-ui 行内编辑组件", 4 | "version": "1.0.3", 5 | "private": false, 6 | "license": "MIT", 7 | "scripts": { 8 | "serve": "vue-cli-service serve", 9 | "build:lib": "vue build -t lib --name vue-ele-editable -d ./dist/ ./src/index.js", 10 | "build": "npm run lint & npm run build:lib", 11 | "lint": "vue-cli-service lint" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/dream2023/vue-ele-editable" 16 | }, 17 | "main": "dist/vue-ele-editable.umd.min.js", 18 | "homepage": "https://github.com/dream2023/vue-ele-editable", 19 | "keywords": [ 20 | "vue-ele-editable", 21 | "editable", 22 | "inline edit", 23 | "edit cell", 24 | "editable table", 25 | "element table", 26 | "el-editable", 27 | "vue editable" 28 | ], 29 | "dependencies": { 30 | "dayjs": "^1.8.14", 31 | "vue-ele-gallery": "^2.1.3", 32 | "vue-ele-upload-image": "^2.0.4" 33 | }, 34 | "devDependencies": { 35 | "@vue/cli-plugin-babel": "^3.8.0", 36 | "@vue/cli-plugin-eslint": "^3.8.0", 37 | "@vue/cli-service": "^3.8.0", 38 | "@vue/eslint-config-standard": "^4.0.0", 39 | "babel-eslint": "^10.0.1", 40 | "core-js": "^2.6.5", 41 | "element-ui": "^2.9.1", 42 | "eslint": "^5.16.0", 43 | "eslint-plugin-vue": "^5.0.0", 44 | "lint-staged": "^8.1.5", 45 | "vue": "^2.6.10", 46 | "vue-template-compiler": "^2.6.10" 47 | }, 48 | "eslintConfig": { 49 | "root": true, 50 | "env": { 51 | "node": true 52 | }, 53 | "extends": [ 54 | "plugin:vue/essential", 55 | "@vue/standard" 56 | ], 57 | "rules": {}, 58 | "parserOptions": { 59 | "parser": "babel-eslint" 60 | } 61 | }, 62 | "postcss": { 63 | "plugins": { 64 | "autoprefixer": {} 65 | } 66 | }, 67 | "browserslist": [ 68 | "> 1%", 69 | "last 2 versions" 70 | ], 71 | "gitHooks": { 72 | "pre-commit": "lint-staged" 73 | }, 74 | "lint-staged": { 75 | "src/*.{js,vue}": [ 76 | "vue-cli-service lint", 77 | "git add" 78 | ] 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /public/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dream2023/vue-ele-editable/6096c0061f73f18153dcc8c7525d31863bcfeea8/public/example.gif -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dream2023/vue-ele-editable/6096c0061f73f18153dcc8c7525d31863bcfeea8/public/favicon.ico -------------------------------------------------------------------------------- /public/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dream2023/vue-ele-editable/6096c0061f73f18153dcc8c7525d31863bcfeea8/public/img/1.png -------------------------------------------------------------------------------- /public/img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dream2023/vue-ele-editable/6096c0061f73f18153dcc8c7525d31863bcfeea8/public/img/2.png -------------------------------------------------------------------------------- /public/img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dream2023/vue-ele-editable/6096c0061f73f18153dcc8c7525d31863bcfeea8/public/img/3.png -------------------------------------------------------------------------------- /public/img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dream2023/vue-ele-editable/6096c0061f73f18153dcc8c7525d31863bcfeea8/public/img/4.png -------------------------------------------------------------------------------- /public/img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dream2023/vue-ele-editable/6096c0061f73f18153dcc8c7525d31863bcfeea8/public/img/5.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vue-ele-editable 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/EleEditable.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 353 | 354 | 378 | -------------------------------------------------------------------------------- /src/EleEditableMixin.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs' 2 | 3 | export default { 4 | // 不继承父组件隐式绑定的属性 5 | inheritAttrs: false, 6 | props: { 7 | // 类型 8 | type: { 9 | type: String, 10 | required: true 11 | }, 12 | // 用于还原失败后newValue的值 13 | isError: Boolean, 14 | // 选项 (select, checkbox, radio) 15 | options: Array, 16 | // 弹窗标题 17 | title: String, 18 | // 自定义属性 19 | customAttrs: Object, 20 | // 原始值 21 | value: [String, Number, Boolean, Array, Date], 22 | // 计算后的值 23 | computedValue: [String, Number, Boolean, Array, Date], 24 | // 显示的值 25 | displayValue: [String, Number, Boolean, Array, Date], 26 | // 是否不需要包裹 27 | noWrapper: { 28 | type: Boolean, 29 | required: true 30 | } 31 | }, 32 | computed: { 33 | // 全局参数 34 | globalEditableParams () { 35 | return this.$EleEditableParams || {} 36 | }, 37 | // 组件属性: 默认属性和自定义属性的融合 38 | attrs () { 39 | return Object.assign( 40 | {}, 41 | this.globalEditableParams[this.type] || {}, 42 | this.defaultAttrs || {}, 43 | this.customAttrs 44 | ) 45 | }, 46 | format () { 47 | let format = 48 | this.attrs && this.attrs.format ? this.attrs.format : 'yyyy-MM-dd' 49 | format = format.replace(/Y/g, 'y') 50 | format = format.replace(/D/g, 'd') 51 | return format 52 | }, 53 | showFormat () { 54 | let format = 55 | this.attrs && this.attrs.format ? this.attrs.format : 'yyyy-MM-dd' 56 | format = format.replace(/y/g, 'Y') 57 | format = format.replace(/d/g, 'D') 58 | return format 59 | } 60 | }, 61 | data () { 62 | return { 63 | // 用于组件 v-model 绑定值 64 | newValue: this.computedValue 65 | } 66 | }, 67 | watch: { 68 | // 检测是否出错, 出错后进行还原值 69 | isError (value) { 70 | if (value) { 71 | this.setNewValue() 72 | } 73 | }, 74 | // 当检测到值变化时, 进行设置新值 75 | computedValue () { 76 | this.setNewValue() 77 | } 78 | }, 79 | methods: { 80 | // 设置新值 81 | setNewValue () { 82 | this.newValue = this.computedValue 83 | }, 84 | // 提交 85 | handleChange (value) { 86 | if (this.noWrapper) { 87 | this.$emit('change', value) 88 | } else { 89 | this.$emit('update', value) 90 | } 91 | }, 92 | // 取消(还原值) 93 | handleCancel () { 94 | this.setNewValue() 95 | }, 96 | // 日期和时间特殊处理 97 | setTimeNewValue () { 98 | const value = 99 | typeof this.computedValue === 'number' 100 | ? this.computedValue * 1000 101 | : this.computedValue 102 | if (dayjs(value).isValid()) { 103 | this.newValue = dayjs(value).format(this.showFormat) 104 | } else { 105 | this.newValue = value 106 | } 107 | }, 108 | // 日期和时间特殊处理 109 | handleTimeChange (value) { 110 | if (value) { 111 | if (typeof this.value === 'number') { 112 | value = dayjs(value).unix() 113 | } else { 114 | if (dayjs(value).isValid()) { 115 | value = dayjs(value).format(this.showFormat) 116 | } 117 | } 118 | } 119 | this.handleChange(value) 120 | } 121 | }, 122 | mounted () { 123 | // 初始化 124 | this.setNewValue() 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/EleEditableWrapper.vue: -------------------------------------------------------------------------------- 1 | 92 | 93 | 206 | -------------------------------------------------------------------------------- /src/components/EleCommonTime.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 30 | -------------------------------------------------------------------------------- /src/components/EleEditableCheckbox.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /src/components/EleEditableColor.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /src/components/EleEditableDate.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | -------------------------------------------------------------------------------- /src/components/EleEditableDateText.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 33 | -------------------------------------------------------------------------------- /src/components/EleEditableDatetime.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 34 | -------------------------------------------------------------------------------- /src/components/EleEditableDatetimeText.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | -------------------------------------------------------------------------------- /src/components/EleEditableImage.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 30 | -------------------------------------------------------------------------------- /src/components/EleEditableInput.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /src/components/EleEditableNumber.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /src/components/EleEditableRadio.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /src/components/EleEditableSelect.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 27 | -------------------------------------------------------------------------------- /src/components/EleEditableStatus.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 32 | -------------------------------------------------------------------------------- /src/components/EleEditableSwitch.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 36 | -------------------------------------------------------------------------------- /src/components/EleEditableText.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | -------------------------------------------------------------------------------- /src/components/EleEditableTextarea.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /src/components/EleEditableTime.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 38 | -------------------------------------------------------------------------------- /src/components/EleEditableTimeText.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | -------------------------------------------------------------------------------- /src/components/EleEditableUploadImage.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | 25 | 34 | -------------------------------------------------------------------------------- /src/components/EleEditableUrl.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import EleEditable from './EleEditable' 2 | 3 | const Plugin = {} 4 | 5 | Plugin.install = function (Vue, params = {}) { 6 | Vue.prototype.$EleEditableParams = params 7 | Vue.component(EleEditable.name, EleEditable) 8 | } 9 | 10 | if (typeof window !== 'undefined' && window.Vue) { 11 | Plugin.install(window.Vue) 12 | } 13 | 14 | export { EleEditable } 15 | export default Plugin 16 | -------------------------------------------------------------------------------- /src/wrapper/EleEditableWrapperDisplay.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 62 | -------------------------------------------------------------------------------- /src/wrapper/EleEditableWrapperForm.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 46 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | css: { extract: false }, 3 | configureWebpack: { 4 | entry: './example/main.js', 5 | output: { 6 | libraryExport: 'default' 7 | } 8 | } 9 | } 10 | --------------------------------------------------------------------------------