Merge pull request #1 from ElemeFE/dev

update to new
pull/1406/head
Leon Zhang 2016-11-28 10:01:36 +08:00 committed by GitHub
commit 640ac48ef5
55 changed files with 642 additions and 342 deletions

View File

@ -14,6 +14,7 @@
- [Home Page](http://element.eleme.io/)
- [Docs](http://element.eleme.io/#/component)
- [FAQ](./FAQ.md)
- [Customize Theme](http://element.eleme.io/#/en-US/component/custom-theme)
- Starter Kit
- [element-starter](https://github.com/ElementUI/element-starter)
- [element-cooking-starter](https://github.com/ElementUI/element-cooking-starter)

View File

@ -4,7 +4,7 @@ Element uses BEM-styled CSS so that you can override styles easily. But if you n
### Install related tool
First install the theme generator globally or locally. Local install is recommended because in this way, when others clone your project, npm will automatically install it for them.
```shell
npm i element-theme -D
npm i element-theme -g
```
Then install the default theme from npm or GitHub.
@ -20,7 +20,7 @@ npm i https://github.com/ElementUI/theme-default -D
After successfully installing the above packages, a command named `et` is available in CLI (if the packages are installed locally, use `node_modules/.bin/et` instead). Run `-i` to initialize the variable file which outputs to `element-variables.css` by default. And you can specify its output directory as you will.
```shell
node_modules/.bin/et -i [custom output directory]
et -i [custom output directory]
> ✔ Generator variables file
```
@ -53,7 +53,7 @@ Just edit `element-variables.css`, e.g. changing the theme color to red:
### Build theme
After saving the variable file, use `et` to build your theme. You can activate `watch` mode by adding a parameter `-w`:
```shell
node_modules/.bin/et
et
> ✔ build theme font
> ✔ build element theme

View File

@ -6,10 +6,10 @@
return callback(new Error('Please input the age'));
}
setTimeout(() => {
if (!Number.isInteger(age)) {
if (!Number.isInteger(value)) {
callback(new Error('Please input digits'));
} else{
if (age < 18) {
} else {
if (value < 18) {
callback(new Error('Age must be greater than 18'));
} else {
callback();
@ -117,7 +117,7 @@
{ validator: validaePass2, trigger: 'blur' }
],
age: [
{ validator: checkAge, trigger: 'change', trigger: 'blur' }
{ validator: checkAge, trigger: 'blur' }
]
},
dynamicForm: {
@ -172,6 +172,9 @@
handleReset2() {
this.$refs.ruleForm2.resetFields();
},
handleReset3() {
this.$refs.dynamicForm.resetFields();
},
handleValidate(prop, errorMsg) {
console.log(prop, errorMsg);
},
@ -632,7 +635,7 @@ Form component allows you to verify your data, helping you find and correct erro
<el-input type="password" v-model="ruleForm2.checkPass" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="Age" prop="age">
<el-input v-model="ruleForm2.age"></el-input>
<el-input v-model.number="ruleForm2.age"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit2">Submit</el-button>
@ -647,10 +650,10 @@ Form component allows you to verify your data, helping you find and correct erro
return callback(new Error('Please input the age'));
}
setTimeout(() => {
if (!Number.isInteger(age)) {
if (!Number.isInteger(value)) {
callback(new Error('Please input digits'));
} else{
if (age < 18) {
} else {
if (value < 18) {
callback(new Error('Age must be greater than 18'));
} else {
callback();
@ -691,7 +694,7 @@ Form component allows you to verify your data, helping you find and correct erro
{ validator: validaePass2, trigger: 'blur' }
],
age: [
{ validator: checkAge, trigger: 'change', trigger: 'blur' }
{ validator: checkAge, trigger: 'blur' }
]
}
};
@ -729,12 +732,9 @@ Form component allows you to verify your data, helping you find and correct erro
v-for="(domain, index) in dynamicForm.domains"
:label="'Domain' + index"
:key="domain.key"
:prop="'domains:' + index"
:prop="'domains.' + index + '.value'"
:rules="{
type: 'object', required: true,
fields: {
value: { required: true, message: 'domain can not be null', trigger: 'blur' }
}
required: true, message: 'domain can not be null', trigger: 'blur'
}"
>
<el-input v-model="domain.value"></el-input><el-button @click.prevent="removeDomain(domain)">Delete</el-button>
@ -742,6 +742,7 @@ Form component allows you to verify your data, helping you find and correct erro
<el-form-item>
<el-button type="primary" @click="handleSubmit3">Submit</el-button>
<el-button @click="addDomain">New domain</el-button>
<el-button @click="handleReset3">Reset</el-button>
</el-form-item>
</el-form>
<script>
@ -774,15 +775,18 @@ Form component allows you to verify your data, helping you find and correct erro
}
});
},
handleReset3() {
this.$refs.dynamicForm.resetFields();
},
removeDomain(item) {
var index = this.dynamicForm.domains.indexOf(item)
var index = this.dynamicForm.domains.indexOf(item);
if (index !== -1) {
this.dynamicForm.domains.splice(index, 1)
this.dynamicForm.domains.splice(index, 1);
}
},
addDomain() {
this.dynamicForm.domains.push({
key: this.dynamicForm.domains.length,
key: Date.now(),
value: ''
});
}

View File

@ -110,17 +110,14 @@
display: inline-block;
}
.inline-input {
.el-input {
&.el-input {
display: inline-block;
vertical-align: top;
margin: 10px 5px;
}
.el-autocomplete {
&.el-autocomplete {
display: inline-block;
margin: 10px 0 0;
.el-input {
margin: 0;
}
}
}
.tac {
@ -306,22 +303,26 @@ export default {
::: demo Add `size` attribute to change the size of Input. In addition to the default size, there are three other options: `large`, `small` and `mini`.
```html
<div class="inline-input">
<div>
<el-input
class="inline-input"
size="large"
placeholder="Please input"
v-model="input6">
</el-input>
<el-input
class="inline-input"
placeholder="Please input"
v-model="input7">
</el-input>
<el-input
class="inline-input"
size="small"
placeholder="Please input"
v-model="input8">
</el-input>
<el-input
class="inline-input"
size="mini"
placeholder="Please input"
v-model="input9">
@ -349,10 +350,11 @@ You can get some recommended tips based on the current input.
::: demo Autocomplete component provides input suggestions. The `fetch-suggestions` attribute is a method that returns suggested input. In this example, `querySearch(queryString, cb)` returns suggestions to Autocomplete via `cb(data)` when suggestions are ready.
```html
<el-row class="inline-input border-grid">
<el-row class="border-grid">
<el-col :span="12" class="tac">
<div class="text">list suggestions when activated</div>
<el-autocomplete
class="inline-input"
v-model="state1"
:fetch-suggestions="querySearch"
placeholder="Please input"
@ -362,6 +364,7 @@ You can get some recommended tips based on the current input.
<el-col :span="12" class="tac">
<div class="text">list suggestions on input</div>
<el-autocomplete
class="inline-input"
v-model="state2"
:fetch-suggestions="querySearch"
placeholder="Please input"

View File

@ -1,7 +1,7 @@
## Installation
### npm
Installing with npm is recommended, for it works seamlessly with [webpack](https://webpack.js.org/).
Installing with npm is recommended and it works seamlessly with [webpack](https://webpack.js.org/).
```shell
npm i element-ui -D

View File

@ -22,7 +22,7 @@ Menu that provides navigation for your website.
Top bar NavMenu can be used in a variety of scenarios.
::: demo
::: demo By default Menu is vertical, but you can change it to horizontal by setting the mode prop to 'horizontal'. In addition, you can use the submenu component to create a second level menu.
```html
<el-menu theme="dark" default-active="1" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="1">Processing Center</el-menu-item>
@ -62,7 +62,7 @@ Top bar NavMenu can be used in a variety of scenarios.
Vertical NavMenu with sub-menus.
::: demo
::: demo You can use the el-menu-item-group component to create a menu group, and the name of the group is determined by the title prop or a named slot.
```html
<el-row class="tac">
<el-col :span="8">

View File

@ -137,5 +137,7 @@ change | triggers when the bound value changes | the label value of the chosen r
---- | ---- | ---- | ---- | ----
label | the value of radio | string/number | — | —
disabled | whether radio is disabled | boolean | — | false
fill | border and background color when button is active | string | — | #20a0ff |
text-color | font color when button is active | string | — | #ffffff |

View File

@ -1183,7 +1183,8 @@ Customize table column so it can be integrated with other components.
| fit | whether width of column automatically fits its container | boolean | — | true |
| show-header | whether table header is visible | boolean | - | true |
| highlight-current-row | whether current row is highlighted | boolean | — | false |
| row-class-name | function that returns custom class names for a row | Function(row, index) | — | — |
| row-class-name | function that returns custom class names for a row, or a string assigning class names for every row | Function(row, index)/String | — | — |
| row-style | function that returns custom style for a row, or a string assigning custom style for every row | Function(row, index)/Object | — | — |
| row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on | Function(row)/String | — | — |
| context | context of Table, e.g. `_self` refers to the current context, `$parent` parent context, `$root` root context, can be overridden by `context` in `el-table-column` | Object | - | current context where Table lies |

View File

@ -1,5 +1,10 @@
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleChange(file, fileList, event) {
console.log(file, fileList, event);
@ -37,12 +42,18 @@ Upload files by clicking or drag-and-drop
<el-upload
action="//jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove">
:on-remove="handleRemove"
:default-file-list="fileList">
<el-button size="small" type="primary">Click to upload</el-button>
<div class="el-upload__tip" slot="tip">jpg/png files with a size less than 500kb</div>
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
@ -70,6 +81,7 @@ You can drag your file to a certain area to upload it.
:on-remove="handleRemove"
:on-success="handleSuccess"
:on-error="handleError"
:default-file-list="fileList"
>
<i class="el-icon-upload"></i>
<div class="el-dragger__text">Drop file here or <em>click to upload</em></div>
@ -77,6 +89,11 @@ You can drag your file to a certain area to upload it.
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
@ -102,6 +119,7 @@ This mode is specifically for image uploading, and the thumbnail will display in
:thumbnail-mode="true"
:on-preview="handlePreview"
:on-remove="handleRemove"
:default-file-list="fileList"
>
<i class="el-icon-upload"></i>
<div class="el-dragger__text">Drop file here or <em>click to upload</em></div>
@ -109,6 +127,11 @@ This mode is specifically for image uploading, and the thumbnail will display in
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
@ -140,6 +163,7 @@ on-success | hook function when uploaded successfully | function(response, file,
on-error | hook function when some errors occurs | function(err, response, file) | — | —
before-upload | hook function before uploading with the file to be uploaded as its parameter. If `false` or a `Promise` is returned, uploading will be aborted | function(file) | — | —
thumbnail-mode | whether thumbnail is displayed | boolean | — | false
default-file-list | default uploaded files, i.e: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}] | array | — | []
### Events
| Event Name | Description | Parameters |

View File

@ -2,9 +2,9 @@
Element 默认提供一套主题CSS 命名采用 BEM 的风格方便使用者覆盖样式。如果你想完全替换主题色或者部分样式,可以使用下面方法。
### 安装工具
首先安装「主题生成工具」,可以全局安装或者安装在当前项目下,推荐安装在项目里,方便别人 clone 项目时能直接安装依赖并启动。
首先安装「主题生成工具」,可以全局安装或者安装在当前项目下,推荐安装在项目里,方便别人 clone 项目时能直接安装依赖并启动,这里以全局安装做演示
```shell
npm i element-theme -D
npm i element-theme -g
```
安装默认主题,可以从 npm 安装或者从 GitHub 拉取最新代码。
@ -20,7 +20,7 @@ npm i https://github.com/ElementUI/theme-default -D
主题生成工具安装成功后,如果全局安装可以在命令行里通过 `et` 调用工具,如果安装在当前目录下,需要通过 `node_modules/.bin/et` 访问到命令。执行 `-i` 初始化变量文件。默认输出到 `element-variables.css`,当然你可以传参数指定文件输出目录。
```shell
node_modules/.bin/et -i [可以自定义变量文件目录]
et -i [可以自定义变量文件目录]
> ✔ Generator variables file
```
@ -53,7 +53,7 @@ node_modules/.bin/et -i [可以自定义变量文件目录]
### 编译主题
保存文件后,到命令行里执行 `et` 编译主题,如果你想启用 `watch` 模式,实时编译主题,增加 `-w` 参数。
```shell
node_modules/.bin/et
et
> ✔ build theme font
> ✔ build element theme

View File

@ -122,8 +122,8 @@
},
dynamicForm: {
domains: [{
key: Date.now(),
value: ''
value: '',
key: Date.now()
}],
email: ''
},
@ -172,6 +172,9 @@
handleReset2() {
this.$refs.ruleForm2.resetFields();
},
handleReset3() {
this.$refs.dynamicForm.resetFields();
},
handleValidate(prop, errorMsg) {
console.log(prop, errorMsg);
},
@ -189,8 +192,8 @@
},
addDomain() {
this.dynamicForm.domains.push({
key: Date.now(),
value: ''
value: '',
key: Date.now()
});
}
}
@ -720,12 +723,9 @@
v-for="(domain, index) in dynamicForm.domains"
:label="'域名' + index"
:key="domain.key"
:prop="'domains:' + index"
:prop="'domains.' + index + '.value'"
:rules="{
type: 'object', required: true,
fields: {
value: { required: true, message: '域名不能为空', trigger: 'blur' }
}
required: true, message: '域名不能为空', trigger: 'blur'
}"
>
<el-input v-model="domain.value"></el-input><el-button @click.prevent="removeDomain(domain)">删除</el-button>
@ -733,6 +733,7 @@
<el-form-item>
<el-button type="primary" @click="handleSubmit3">提交</el-button>
<el-button @click="addDomain">新增域名</el-button>
<el-button @click="handleReset3">重置</el-button>
</el-form-item>
</el-form>
<script>
@ -741,7 +742,6 @@
return {
dynamicForm: {
domains: [{
key: 1,
value: ''
}],
email: ''
@ -765,6 +765,9 @@
}
});
},
handleReset3() {
this.$refs.dynamicForm.resetFields();
},
removeDomain(item) {
var index = this.dynamicForm.domains.indexOf(item)
if (index !== -1) {
@ -773,8 +776,8 @@
},
addDomain() {
this.dynamicForm.domains.push({
key: this.dynamicForm.domains.length,
value: ''
value: '',
key: Date.now()
});
}
}

View File

@ -151,17 +151,14 @@
display: inline-block;
}
.inline-input {
.el-input {
&.el-input {
display: inline-block;
vertical-align: top;
margin: 10px 5px;
}
.el-autocomplete {
&.el-autocomplete {
display: inline-block;
margin: 10px 0 0;
.el-input {
margin: 0;
}
}
}
.tac {
@ -349,22 +346,26 @@ export default {
::: demo 可通过 `size` 属性指定输入框的尺寸,除了默认的大小外,还提供了 large、small 和 mini 三种尺寸。
```html
<div class="inline-input">
<div>
<el-input
class="inline-input"
size="large"
placeholder="请输入内容"
v-model="input6">
</el-input>
<el-input
class="inline-input"
placeholder="请输入内容"
v-model="input7">
</el-input>
<el-input
class="inline-input"
size="small"
placeholder="请输入内容"
v-model="input8">
</el-input>
<el-input
class="inline-input"
size="mini"
placeholder="请输入内容"
v-model="input9">
@ -392,10 +393,11 @@ export default {
::: demo autocomplete 是一个可带输入建议的输入框组件,`fetch-suggestions` 是一个返回输入建议的方法属性,如 querySearch(queryString, cb),在该方法中你可以在你的输入建议数据准备好时通过 cb(data) 返回到 autocomplete 组件中。
```html
<el-row class="inline-input border-grid">
<el-row class="border-grid">
<el-col :span="12" class="tac">
<div class="text">激活即列出输入建议</div>
<el-autocomplete
class="inline-input"
v-model="state1"
:fetch-suggestions="querySearch"
placeholder="请输入内容"
@ -405,6 +407,7 @@ export default {
<el-col :span="12" class="tac">
<div class="text">输入后匹配输入建议</div>
<el-autocomplete
class="inline-input"
v-model="state2"
:fetch-suggestions="querySearch"
placeholder="请输入内容"

View File

@ -52,7 +52,7 @@
适用广泛的基础用法。
::: demo
::: demo 导航菜单默认为垂直模式,通过 `mode` 属性可以使导航菜单变更为水平模式。另外,在菜单中通过 `submenu` 组件可以生成二级菜单。
```html
<el-menu theme="dark" default-active="1" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="1">处理中心</el-menu-item>
@ -92,7 +92,7 @@
垂直菜单,可内嵌子菜单。
::: demo
::: demo 通过 `el-menu-item-group` 组件可以实现菜单进行分组,分组名可以通过 `title` 属性直接设定也可以通过具名 slot 来设定。
```html
<el-row class="tac">
<el-col :span="8">
@ -100,7 +100,8 @@
<el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>导航一</template>
<el-menu-item-group title="分组一">
<el-menu-item-group>
<template slot="title">分组一</template>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
</el-menu-item-group>

View File

@ -138,3 +138,5 @@
|---------- |-------- |---------- |------------- |-------- |
| label | Radio 的 value | string,number | — | — |
| disabled | 是否禁用 | boolean | — | false |
| fill | 按钮激活时的填充色和边框色 | string | — | #20a0ff |
| text-color | 按钮激活时的文本颜色 | string | — | #ffffff |

View File

@ -1188,7 +1188,8 @@
| fit | 列的宽度是否自撑开 | boolean | — | true |
| show-header | 是否显示表头 | boolean | - | true |
| highlight-current-row | 是否要高亮当前行 | boolean | — | false |
| row-class-name | 行的 className 的回调。 | Function(row, index) | — | — |
| row-class-name | 行的 className 的回调方法,也可以使用字符串为所有行设置一个固定的 className。 | Function(row, index)/String | — | — |
| row-style | 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。 | Function(row, index)/Object | — | — |
| row-key | 行数据的 Key用来优化 Table 的渲染;在使用 reserve-selection 功能的情况下,该属性是必填的 | Function(row)/String | — | — |
| context | 设置上下文环境,例如设置当前上下文就是 `_self`,父级就是 `$parent`,根组件 `$root`。优先读取 column 的 context 属性。 | Object | - | Table 所处上下文 |

View File

@ -10,6 +10,11 @@
</style>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleChange(file, fileList, event) {
console.log(file, fileList, event);
@ -48,12 +53,18 @@
<el-upload
action="//jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove">
:on-remove="handleRemove"
:default-file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件且不超过500kb</div>
<div class="el-upload__tip" slot="tip" @click="changeFiles">只能上传jpg/png文件且不超过500kb</div>
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
@ -81,6 +92,7 @@
:on-remove="handleRemove"
:on-success="handleSuccess"
:on-error="handleError"
:default-file-list="fileList"
>
<i class="el-icon-upload"></i>
<div class="el-dragger__text">将文件拖到此处,或<em>点击上传</em></div>
@ -88,6 +100,11 @@
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
@ -113,6 +130,7 @@
:thumbnail-mode="true"
:on-preview="handlePreview"
:on-remove="handleRemove"
:default-file-list="fileList"
>
<i class="el-icon-upload"></i>
<div class="el-dragger__text">将文件拖到此处,或<em>点击上传</em></div>
@ -120,6 +138,11 @@
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
@ -151,6 +174,7 @@
| on-error | 可选参数, 文件上传失败时的钩子 | function(err, response, file) | — | — |
| before-upload | 可选参数, 上传文件之前的钩子,参数为上传的文件,若返回 false 或者 Promise 则停止上传。 | function(file) | — | — |
| thumbnail-mode | 是否设置为图片模式,该模式下会显示图片缩略图 | boolean | — | false |
| default-file-list | 默认已上传的文件列表, 例如: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}] | array | — | [] |
### Upload Methods
| 方法名 | 说明 | 参数 |

View File

@ -11,7 +11,14 @@
@keydown.up.native="highlight(highlightedIndex - 1)"
@keydown.down.native="highlight(highlightedIndex + 1)"
@keydown.enter.native="select(highlightedIndex)"
></el-input>
>
<template slot="prepend" v-if="$slots.prepend">
<slot name="prepend"></slot>
</template>
<template slot="append" v-if="$slots.append">
<slot name="append"></slot>
</template>
</el-input>
<transition name="md-fade-bottom">
<ul
v-if="suggestionVisible"

View File

@ -15,8 +15,13 @@
watch: {
value(value) {
this.$emit('change', value);
this.dispatch('form-item', 'el.form.change', [value]);
this.dispatch('ElFormItem', 'el.form.change', [value]);
this.broadcast('ElCheckbox', 'initData', [value]);
}
},
mounted() {
this.broadcast('ElCheckbox', 'initData', [this.value]);
}
};
</script>

View File

@ -17,11 +17,10 @@
:disabled="disabled"
:true-value="trueLabel"
:false-value="falseLabel"
v-model="_value"
v-model="model"
@change="$emit('change', $event)"
@focus="focus = true"
@blur="focus = false"
@change="handleChange"
ref="checkbox">
@blur="focus = false">
<input
v-else
class="el-checkbox__original"
@ -29,10 +28,10 @@
:disabled="disabled"
:value="label"
:name="name"
v-model="_value"
v-model="model"
@change="$emit('change', $event)"
@focus="focus = true"
@blur="focus = false"
@change="handleChange">
@blur="focus = false">
</span>
<span class="el-checkbox__label" v-if="$slots.default || label">
<slot></slot>
@ -48,9 +47,37 @@
mixins: [Emitter],
componentName: 'ElCheckbox',
computed: {
model: {
get() {
return this.isGroup ? this.store : this.value;
},
set(val) {
if (this.isGroup) {
this.dispatch('ElCheckboxGroup', 'input', [val]);
} else {
this.$emit('input', val);
}
}
},
isChecked() {
if ({}.toString.call(this.model) === '[object Boolean]') {
return this.model;
} else if (Array.isArray(this.model)) {
return this.model.indexOf(this.label) > -1;
} else if (this.model !== null && this.model !== undefined) {
return this.model === this.trueLabel;
}
}
},
props: {
value: {},
label: String,
label: {},
indeterminate: Boolean,
disabled: Boolean,
checked: Boolean,
@ -59,59 +86,30 @@
falseLabel: [String, Number]
},
computed: {
_value: {
get() {
return !this.wrapInGroup ? this.value : this.$parent.value;
},
set(newValue) {
if (!this.wrapInGroup) {
this.$emit('input', newValue);
} else {
this.$parent.$emit('input', newValue);
}
}
},
isChecked() {
var type = Object.prototype.toString.call(this._value);
if (type === '[object Boolean]') {
return this._value;
} else if (type === '[object Array]') {
return this._value.indexOf(this.label) > -1;
} else if (type === '[object String]' || type === '[object Number]') {
return this._value === this.trueLabel;
}
}
},
data() {
return {
focus: false,
wrapInGroup: this.$parent.$options.componentName === 'ElCheckboxGroup'
store: [],
isGroup: false
};
},
watch: {
checked: {
immediate: true,
handler(value) {
if (value) {
let type = Object.prototype.toString.call(this._value);
if (type !== '[object Array]') {
this._value = this.trueLabel || true;
} else {
this._value.push(this.label);
}
}
}
}
},
methods: {
handleChange(ev) {
this.$emit('change', ev);
addToStore() {
if (Array.isArray(this.model)) {
this.model.indexOf(this.label) === -1 && this.model.push(this.label);
} else {
this.model = this.trueLabel || true;
}
}
},
created() {
this.checked && this.addToStore();
this.$on('initData', data => {
this.store = data;
this.isGroup = true;
this.checked && this.addToStore();
});
}
};
</script>

View File

@ -50,9 +50,7 @@
props: {
disabledDate: {},
date: {},
year: {
type: Number
}
year: {}
},
computed: {
@ -86,7 +84,7 @@
const target = event.target;
if (target.tagName === 'A') {
if (hasClass(target.parentNode, 'disabled')) return;
const year = parseInt(target.textContent || target.innerText, 10);
const year = target.textContent || target.innerText;
this.$emit('pick', year);
}
}

View File

@ -183,7 +183,7 @@
methods: {
handleClear() {
this.date = new Date();
this.$emit('pick');
this.$emit('pick', '');
},
resetDate() {
@ -310,7 +310,7 @@
this.date.setFullYear(year);
if (this.selectionMode === 'year') {
this.$emit('pick', year);
this.$emit('pick', new Date(year));
} else {
this.currentView = 'month';
}

View File

@ -84,7 +84,7 @@
},
handleClear() {
this.$emit('pick');
this.$emit('pick', '');
}
},

View File

@ -101,7 +101,7 @@
methods: {
handleClear() {
this.handleCancel();
this.$emit('pick', '');
},
handleCancel() {

View File

@ -58,7 +58,8 @@ const DEFAULT_FORMATS = {
time: 'HH:mm:ss',
timerange: 'HH:mm:ss',
daterange: 'yyyy-MM-dd',
datetimerange: 'yyyy-MM-dd HH:mm:ss'
datetimerange: 'yyyy-MM-dd HH:mm:ss',
year: 'yyyy'
};
const HAVE_TRIGGER_TYPES = [
'date',
@ -163,16 +164,8 @@ const TYPE_VALUE_RESOLVER_MAP = {
parser: DATE_PARSER
},
year: {
formatter(value) {
if (!value) return '';
return '' + value;
},
parser(text) {
const year = Number(text);
if (!isNaN(year)) return year;
return null;
}
formatter: DATE_FORMATTER,
parser: DATE_PARSER
},
number: {
formatter(value) {
@ -236,7 +229,7 @@ export default {
if (!val && this.picker && typeof this.picker.handleClear === 'function') {
this.picker.handleClear();
}
this.dispatch('form-item', 'el.form.change');
this.dispatch('ElFormItem', 'el.form.change');
},
value: {
immediate: true,
@ -358,7 +351,7 @@ export default {
handleBlur() {
this.$emit('blur', this);
this.dispatch('form-item', 'el.form.blur');
this.dispatch('ElFormItem', 'el.form.blur');
},
handleKeydown(event) {

View File

@ -21,10 +21,33 @@
function noop() {}
function getPropByPath(obj, path) {
let tempObj = obj;
path = path.replace(/\[(\w+)\]/g, '.$1');
path = path.replace(/^\./, '');
let keyArr = path.split('.');
let i = 0;
for (let len = keyArr.length; i < len - 1; ++i) {
let key = keyArr[i];
if (key in tempObj) {
tempObj = tempObj[key];
} else {
throw new Error('please transfer a valid prop path to form item!');
}
}
return {
o: tempObj,
k: keyArr[i],
v: tempObj[keyArr[i]]
};
}
export default {
name: 'ElFormItem',
componentName: 'form-item',
componentName: 'ElFormItem',
mixins: [emitter],
@ -65,7 +88,7 @@
},
form() {
var parent = this.$parent;
while (parent.$options.componentName !== 'form') {
while (parent.$options.componentName !== 'ElForm') {
parent = parent.$parent;
}
return parent;
@ -76,11 +99,12 @@
var model = this.form.model;
if (!model || !this.prop) { return; }
var temp = this.prop.split(':');
var path = this.prop;
if (path.indexOf(':') !== -1) {
path = path.replace(/:/, '.');
}
return temp.length > 1
? model[temp[0]][temp[1]]
: model[this.prop];
return getPropByPath(model, path).v;
}
}
},
@ -124,13 +148,19 @@
let model = this.form.model;
let value = this.fieldValue;
let path = this.prop;
if (path.indexOf(':') !== -1) {
path = path.replace(/:/, '.');
}
let prop = getPropByPath(model, path);
if (Array.isArray(value) && value.length > 0) {
this.validateDisabled = true;
model[this.prop] = [];
prop.o[prop.k] = [];
} else if (value) {
this.validateDisabled = true;
model[this.prop] = this.initialValue;
prop.o[prop.k] = this.initialValue;
}
},
getRules() {
@ -162,10 +192,10 @@
},
mounted() {
if (this.prop) {
this.dispatch('form', 'el.form.addField', [this]);
this.dispatch('ElForm', 'el.form.addField', [this]);
Object.defineProperty(this, 'initialValue', {
value: this.form.model[this.prop]
value: this.fieldValue
});
let rules = this.getRules();
@ -183,7 +213,7 @@
}
},
beforeDestroy() {
this.dispatch('form', 'el.form.removeField', [this]);
this.dispatch('ElForm', 'el.form.removeField', [this]);
}
};
</script>

View File

@ -10,7 +10,7 @@
export default {
name: 'ElForm',
componentName: 'form',
componentName: 'ElForm',
props: {
model: Object,
@ -23,51 +23,50 @@
},
inline: Boolean
},
watch: {
rules() {
this.validate();
}
},
data() {
return {
fields: {},
fieldLength: 0
fields: []
};
},
created() {
this.$on('el.form.addField', (field) => {
this.fields[field.prop] = field;
this.fieldLength++;
if (field) {
this.fields.push(field);
}
});
/* istanbul ignore next */
this.$on('el.form.removeField', (field) => {
if (this.fields[field.prop]) {
delete this.fields[field.prop];
this.fieldLength--;
if (field.prop) {
this.fields.splice(this.fields.indexOf(field), 1);
}
});
},
methods: {
resetFields() {
for (let prop in this.fields) {
let field = this.fields[prop];
this.fields.forEach(field => {
field.resetField();
}
});
},
validate(callback) {
var count = 0;
var valid = true;
for (let prop in this.fields) {
let field = this.fields[prop];
let valid = true;
this.fields.forEach((field, index) => {
field.validate('', errors => {
if (errors) {
valid = false;
}
if (++count === this.fieldLength) {
if (typeof callback === 'function' && index === this.fields.length - 1) {
callback(valid);
}
});
}
});
},
validateField(prop, cb) {
var field = this.fields[prop];
var field = this.fields.filter(field => field.prop === prop)[0];
if (!field) { throw new Error('must call validateField with valid prop string!'); }
field.validate('', cb);

View File

@ -68,6 +68,8 @@
export default {
name: 'ElInput',
componentName: 'ElInput',
mixins: [emitter],
props: {
@ -105,7 +107,7 @@
methods: {
handleBlur(event) {
this.$emit('blur', event);
this.dispatch('form-item', 'el.form.blur', [this.currentValue]);
this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]);
},
inputSelect() {
this.$refs.input.select();
@ -148,7 +150,7 @@
computed: {
validating() {
return this.$parent.validating;
return this.$parent.validateState === 'validating';
}
},
@ -162,7 +164,7 @@
});
this.$emit('input', val);
this.$emit('change', val);
this.dispatch('form-item', 'el.form.change', [val]);
this.dispatch('ElFormItem', 'el.form.change', [val]);
}
}
};

View File

@ -6,8 +6,7 @@
props: {
title: {
type: String,
required: true
type: String
}
},
data() {
@ -39,7 +38,10 @@
<template>
<li class="el-menu-item-group">
<div class="el-menu-item-group__title" :style="{'padding-left': paddingLeft + 'px'}">{{title}}</div>
<div class="el-menu-item-group__title" :style="{'padding-left': paddingLeft + 'px'}">
<template v-if="!$slots.title">{{title}}</template>
<slot v-else name="title"></slot>
</div>
<ul>
<slot></slot>
</ul>

View File

@ -54,7 +54,7 @@ export default {
jumper: <jumper></jumper>,
pager: <pager currentPage={ this.internalCurrentPage } pageCount={ this.internalPageCount } on-change={ this.handleCurrentChange }></pager>,
next: <next></next>,
sizes: <sizes></sizes>,
sizes: <sizes pageSizes={ this.pageSizes }></sizes>,
slot: <slot></slot>,
total: <total></total>
};
@ -119,11 +119,20 @@ export default {
Sizes: {
mixins: [Locale],
created() {
if (Array.isArray(this.$parent.pageSizes)) {
this.$parent.internalPageSize = this.$parent.pageSizes.indexOf(this.$parent.pageSize) > -1
props: {
pageSizes: Array
},
watch: {
pageSizes: {
immediate: true,
handler(value) {
if (Array.isArray(value)) {
this.$parent.internalPageSize = value.indexOf(this.$parent.pageSize) > -1
? this.$parent.pageSize
: this.$parent.pageSizes[0];
: this.pageSizes[0];
}
}
}
},
@ -136,7 +145,7 @@ export default {
on-change={ this.handleChange }
width={ 110 }>
{
this.$parent.pageSizes.map(item =>
this.pageSizes.map(item =>
<el-option
value={ item }
label={ item + ' ' + this.t('el.pagination.pagesize') }>

View File

@ -23,6 +23,13 @@
set(newValue) {
this.$parent.$emit('input', newValue);
}
},
activeStyle() {
return {
backgroundColor: this.$parent.fill,
borderColor: this.$parent.fill,
color: this.$parent.textColor
};
}
}
};
@ -43,7 +50,7 @@
v-model="value"
:name="name"
:disabled="disabled">
<span class="el-radio-button__inner">
<span class="el-radio-button__inner" :style="value === label ? activeStyle : null">
<slot></slot>
<template v-if="!$slots.default">{{label}}</template>
</span>

View File

@ -4,19 +4,31 @@
export default {
name: 'ElRadioGroup',
componentName: 'radio-group',
componentName: 'ElRadioGroup',
mixins: [Emitter],
props: {
value: [String, Number],
size: String
size: String,
fill: {
type: String,
default: '#20a0ff'
},
textColor: {
type: String,
default: '#fff'
}
},
watch: {
value(value) {
this.$emit('change', value);
this.dispatch('form-item', 'el.form.change', [this.value]);
this.broadcast('ElRadio', 'initData', value);
this.dispatch('ElFormItem', 'el.form.change', [this.value]);
}
},
mounted() {
this.broadcast('ElRadio', 'initData', this.value);
}
};
</script>

View File

@ -4,14 +4,14 @@
<span class="el-radio__inner"
:class="{
'is-disabled': disabled,
'is-checked': _value === label,
'is-checked': store === label,
'is-focus': focus
}"></span>
<input
class="el-radio__original"
:value="label"
type="radio"
v-model="_value"
v-model="store"
@focus="focus = true"
@blur="focus = false"
:name="name"
@ -24,9 +24,15 @@
</label>
</template>
<script>
import Emitter from 'element-ui/src/mixins/emitter';
export default {
name: 'ElRadio',
mixins: [Emitter],
componentName: 'ElRadio',
props: {
value: [String, Number],
label: {
@ -36,24 +42,34 @@
disabled: Boolean,
name: String
},
data() {
return {
focus: false
focus: false,
isGroup: false,
store: this.value
};
},
computed: {
_value: {
get() {
return this.value !== undefined ? this.value : this.$parent.value;
},
set(newValue) {
if (this.value !== undefined) {
this.$emit('input', newValue);
watch: {
store(store) {
if (this.isGroup) {
this.dispatch('ElRadioGroup', 'input', store);
} else {
this.$parent.$emit('input', newValue);
}
this.$emit('input', store);
}
},
value(val) {
this.store = val;
}
},
created() {
this.$on('initData', data => {
this.store = data;
this.isGroup = true;
});
}
};
</script>

View File

@ -27,13 +27,13 @@
watch: {
disabled(val) {
this.broadcast('option', 'handleGroupDisabled', val);
this.broadcast('ElOption', 'handleGroupDisabled', val);
}
},
mounted() {
if (this.disabled) {
this.broadcast('option', 'handleGroupDisabled', this.disabled);
this.broadcast('ElOption', 'handleGroupDisabled', this.disabled);
}
}
};

View File

@ -19,7 +19,7 @@
name: 'el-option',
componentName: 'option',
componentName: 'ElOption',
props: {
value: {
@ -50,6 +50,10 @@
return this.label || ((typeof this.value === 'string' || typeof this.value === 'number') ? this.value : '');
},
currentValue() {
return this.value || this.label || '';
},
parent() {
let result = this.$parent;
while (!result.isSelect) {
@ -74,7 +78,7 @@
watch: {
currentSelected(val) {
if (val === true) {
this.dispatch('select', 'addOptionToValue', this);
this.dispatch('ElSelect', 'addOptionToValue', this);
}
}
},
@ -92,7 +96,7 @@
selectOptionClick() {
if (this.disabled !== true && this.groupDisabled !== true) {
this.dispatch('select', 'handleOptionClick', this);
this.dispatch('ElSelect', 'handleOptionClick', this);
}
},
@ -119,7 +123,7 @@
this.index = this.parent.options.indexOf(this);
if (this.currentSelected === true) {
this.dispatch('select', 'addOptionToValue', [this, true]);
this.dispatch('ElSelect', 'addOptionToValue', [this, true]);
}
this.$on('queryChange', this.queryChange);
@ -128,7 +132,7 @@
},
beforeDestroy() {
this.dispatch('select', 'onOptionDestroy', this);
this.dispatch('ElSelect', 'onOptionDestroy', this);
}
};
</script>

View File

@ -13,7 +13,7 @@
export default {
name: 'el-select-dropdown',
componentName: 'select-dropdown',
componentName: 'ElSelectDropdown',
mixins: [Popper],

View File

@ -82,7 +82,7 @@
name: 'ElSelect',
componentName: 'select',
componentName: 'ElSelect',
computed: {
iconClass() {
@ -97,6 +97,7 @@
let criteria = this.clearable && this.inputHovering && !this.multiple && this.options.indexOf(this.selected) > -1;
if (!this.$el) return false;
this.$nextTick(() => {
let icon = this.$el.querySelector('.el-input__icon');
if (icon) {
if (criteria) {
@ -107,6 +108,8 @@
removeClass(icon, 'is-show-close');
}
}
});
return criteria;
},
@ -239,7 +242,7 @@
this.$emit('input', result);
this.$emit('change', result);
this.dispatch('form-item', 'el.form.change', val);
this.dispatch('ElFormItem', 'el.form.change', val);
if (this.filterable) {
this.query = '';
this.hoverIndex = -1;
@ -259,7 +262,7 @@
query(val) {
this.$nextTick(() => {
this.broadcast('select-dropdown', 'updatePopper');
this.broadcast('ElSelectDropdown', 'updatePopper');
});
if (this.multiple && this.filterable) {
this.resetInputHeight();
@ -268,12 +271,12 @@
this.hoverIndex = -1;
this.remoteMethod(val);
this.voidRemoteQuery = val === '';
this.broadcast('option', 'resetIndex');
this.broadcast('ElOption', 'resetIndex');
} else if (typeof this.filterMethod === 'function') {
this.filterMethod(val);
} else {
this.filteredOptionsCount = this.optionsCount;
this.broadcast('option', 'queryChange', val);
this.broadcast('ElOption', 'queryChange', val);
}
},
@ -283,7 +286,7 @@
if (this.$el.querySelector('.el-input__icon')) {
removeClass(this.$el.querySelector('.el-input__icon'), 'is-reverse');
}
this.broadcast('select-dropdown', 'destroyPopper');
this.broadcast('ElSelectDropdown', 'destroyPopper');
if (this.$refs.input) {
this.$refs.input.blur();
}
@ -301,13 +304,13 @@
if (icon && !hasClass(icon, 'el-icon-circle-close')) {
addClass(this.$el.querySelector('.el-input__icon'), 'is-reverse');
}
this.broadcast('select-dropdown', 'updatePopper');
this.broadcast('ElSelectDropdown', 'updatePopper');
if (this.filterable) {
this.query = this.selectedLabel;
if (this.multiple) {
this.$refs.input.focus();
} else {
this.broadcast('input', 'inputSelect');
this.broadcast('ElInput', 'inputSelect');
}
}
if (!this.dropdownUl) {
@ -395,7 +398,7 @@
let inputChildNodes = this.$refs.reference.$el.childNodes;
let input = [].filter.call(inputChildNodes, item => item.tagName === 'INPUT')[0];
input.style.height = Math.max(this.$refs.tags.clientHeight + 6, this.size === 'small' ? 28 : 36) + 'px';
this.broadcast('select-dropdown', 'updatePopper');
this.broadcast('ElSelectDropdown', 'updatePopper');
});
},
@ -421,7 +424,7 @@
} else {
let optionIndex = -1;
this.selected.forEach((item, index) => {
if (item === option || item.currentLabel === option.currentLabel) {
if (item === option || item.currentValue === option.currentValue) {
optionIndex = index;
}
});
@ -522,7 +525,7 @@
if (index > -1) {
this.options.splice(index, 1);
}
this.broadcast('option', 'resetIndex');
this.broadcast('ElOption', 'resetIndex');
},
resetInputWidth() {

View File

@ -10,6 +10,7 @@ export default {
required: true
},
rowClassName: [String, Function],
rowStyle: [Object, Function],
fixed: String,
highlight: Boolean
},
@ -33,6 +34,7 @@ export default {
{
this._l(this.data, (row, $index) =>
<tr
style={ this.rowStyle ? this.getRowStyle(row, $index) : null }
key={ this.$parent.rowKey ? this.getKeyOfRow(row, $index) : $index }
on-click={ ($event) => this.handleClick($event, row) }
on-mouseenter={ _ => this.handleMouseEnter($index) }
@ -140,6 +142,14 @@ export default {
}
},
getRowStyle(row, index) {
const rowStyle = this.rowStyle;
if (typeof rowStyle === 'function') {
return rowStyle.call(null, row, index);
}
return rowStyle;
},
getRowClass(row, index) {
const classes = [];
@ -147,7 +157,7 @@ export default {
if (typeof rowClassName === 'string') {
classes.push(rowClassName);
} else if (typeof rowClassName === 'function') {
classes.push(rowClassName.apply(null, [row, index]) || '');
classes.push(rowClassName.call(null, row, index) || '');
}
return classes.join(' ');

View File

@ -24,6 +24,7 @@
:store="store"
:layout="layout"
:row-class-name="rowClassName"
:row-style="rowStyle"
:highlight="highlightCurrentRow"
:style="{ width: layout.bodyWidth ? layout.bodyWidth - (layout.scrollY ? layout.gutterWidth : 0 ) + 'px' : '' }">
</table-body>
@ -56,6 +57,7 @@
:layout="layout"
:highlight="highlightCurrentRow"
:row-class-name="rowClassName"
:row-style="rowStyle"
:style="{ width: layout.fixedWidth ? layout.fixedWidth + 'px' : '' }">
</table-body>
</div>
@ -85,6 +87,7 @@
:store="store"
:layout="layout"
:row-class-name="rowClassName"
:row-style="rowStyle"
:highlight="highlightCurrentRow"
:style="{ width: layout.rightFixedWidth ? layout.rightFixedWidth + 'px' : '' }">
</table-body>
@ -145,6 +148,8 @@
rowClassName: [String, Function],
rowStyle: [Object, Function],
highlightCurrentRow: Boolean,
emptyText: {

View File

@ -60,11 +60,6 @@
top: 100%;
left: 0;
}
& .el-button + .el-button,
& .el-checkbox + .el-checkbox,
& .el-radio + .el-radio {
margin-left: 10px;
}
@when required {
.el-form-item__label:before {

View File

@ -40,6 +40,7 @@
width: 35px;
height: 100%;
right: 0;
top: 0;
text-align: center;
color: var(--input-icon-color);

View File

@ -160,15 +160,6 @@
z-index: -1;
left: -999px;
&:checked {
& + .el-radio-button__inner {
z-index: 1;
background-color: var(--color-primary);
border-color: @background-color;
color: #fff;
}
}
&:disabled {
& + .el-radio-button__inner {
color: var(--button-disabled-color);

View File

@ -145,7 +145,7 @@
& img {
display: block;
width: 100%;
height: auto;
height: 100%;
}
@e progress {

View File

@ -97,15 +97,7 @@ export default class Node {
const defaultExpandedKeys = store.defaultExpandedKeys;
const key = store.key;
if (key && defaultExpandedKeys && defaultExpandedKeys.indexOf(this.key) !== -1) {
if (store.autoExpandParent) {
let parent = this.parent;
while (parent.level > 0) {
parent.expanded = true;
parent = parent.parent;
}
}
this.expand();
this.expand(null, store.autoExpandParent);
}
if (store.lazy) {
@ -213,17 +205,27 @@ export default class Node {
}
}
expand(callback) {
expand(callback, expandParent) {
const done = () => {
if (expandParent) {
let parent = this.parent;
while (parent.level > 0) {
parent.expanded = true;
parent = parent.parent;
}
}
this.expanded = true;
if (callback) callback();
};
if (this.shouldLoadData()) {
this.loadData((data) => {
if (data instanceof Array) {
this.expanded = true;
if (callback) callback();
done();
}
});
} else {
this.expanded = true;
if (callback) callback();
done();
}
}

View File

@ -66,30 +66,30 @@ export default class TreeStore {
}
}
getNodeByData(data) {
const key = typeof data === 'string' ? data : getNodeKey(this.key, data);
getNode(data) {
const key = typeof data !== 'object' ? data : getNodeKey(this.key, data);
return this.nodesMap[key];
}
insertBefore(data, refData) {
const refNode = this.getNodeByData(refData);
const refNode = this.getNode(refData);
refNode.parent.insertBefore({ data }, refNode);
}
insertAfter(data, refData) {
const refNode = this.getNodeByData(refData);
const refNode = this.getNode(refData);
refNode.parent.insertAfter({ data }, refNode);
}
remove(data) {
const node = this.getNodeByData(data);
const node = this.getNode(data);
if (node) {
node.parent.removeChild(node);
}
}
append(data, parentData) {
const parentNode = parentData ? this.getNodeByData(parentData) : this.root;
const parentNode = parentData ? this.getNode(parentData) : this.root;
if (parentNode) {
parentNode.insertChild({ data });
@ -206,6 +206,7 @@ export default class TreeStore {
}
setCheckedKeys(keys, leafOnly = true) {
this.defaultCheckedKeys = keys;
const key = this.key;
const checkedKeys = {};
keys.forEach((key) => {
@ -214,4 +215,14 @@ export default class TreeStore {
this._setCheckedKeys(key, leafOnly, checkedKeys);
}
setDefaultExpandedKeys(keys) {
keys = keys || [];
this.defaultExpandedKeys = keys;
keys.forEach((key) => {
const node = this.getNode(key);
if (node) node.expand(null, this.autoExpandParent);
});
}
};

View File

@ -40,6 +40,7 @@
<script type="text/jsx">
import CollapseTransition from './transition';
import ElCheckbox from 'element-ui/packages/checkbox'
export default {
name: 'el-tree-node',
@ -55,6 +56,7 @@
},
components: {
ElCheckbox,
CollapseTransition,
NodeContent: {
props: {

View File

@ -106,11 +106,16 @@
},
watch: {
defaultCheckedKeys(newVal) {
this.store.defaultCheckedKeys = newVal;
this.store.setDefaultCheckedKey(newVal);
},
defaultExpandedKeys(newVal) {
this.store.defaultExpandedKeys = newVal;
this.store.setDefaultExpandedKeys(newVal);
},
data(newVal) {
this.store.setData(newVal);
},
defaultCheckedKeys(newVal) {
this.store.setDefaultCheckedKey(newVal);
}
},

View File

@ -65,6 +65,12 @@ export default {
onError: {
type: Function,
default: noop
},
defaultFileList: {
type: Array,
default() {
return [];
}
}
},
@ -152,6 +158,20 @@ export default {
}
},
watch: {
defaultFileList: {
immediate: true,
handler(fileList) {
this.fileList = fileList.map(item => {
item.status = 'finished';
item.percentage = 100;
item.uid = Date.now() + this.tempIndex++;
return item;
});
}
}
},
render(h) {
var uploadList;

View File

@ -12,7 +12,7 @@ export default {
startTime: 'Horaire début',
endDate: 'Date fin',
endTime: 'Horaire fin',
year: 'Année',
year: '',
month1: 'Janvier',
month2: 'Février',
month3: 'Mars',

View File

@ -5,7 +5,7 @@ function broadcast(componentName, eventName, params) {
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
broadcast.apply(child, [componentName, eventName].concat(params));
broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}

View File

@ -152,5 +152,10 @@ export default {
this.popperElm &&
this.popperElm.parentNode === document.body &&
document.body.removeChild(this.popperElm);
},
// call destroy in keep-alive mode
deactivated() {
this.$options.beforeDestroy[0].call(this);
}
};

View File

@ -67,6 +67,33 @@ describe('Checkbox', () => {
done();
});
});
it('nested group', done => {
vm = createVue({
template: `
<el-checkbox-group v-model="checkList">
<el-row>
<el-checkbox label="a" ref="a"></el-checkbox>
<el-checkbox label="b" ref="b"></el-checkbox>
<el-checkbox label="c" ref="c"></el-checkbox>
<el-checkbox label="d" ref="d"></el-checkbox>
</el-row>
</el-checkbox-group>
`,
data() {
return {
checkList: []
};
}
}, true);
expect(vm.checkList.length === 0).to.be.true;
vm.$refs.a.$el.click();
vm.$nextTick(_ => {
expect(vm.checkList.indexOf('a') !== -1).to.be.true;
done();
});
});
it('true false label', done => {
vm = createVue({
template: `

View File

@ -192,7 +192,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="活动名称" prop="name">
<el-form-item label="活动名称" prop="name" ref="field">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
@ -216,18 +216,18 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.not.true;
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('请输入活动名称');
expect(field.validateMessage).to.equal('请输入活动名称');
vm.setValue('aaaaa');
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
vm.setValue('aa');
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('请输入活动名称');
expect(field.validateMessage).to.equal('请输入活动名称');
done();
});
});
@ -238,7 +238,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="活动名称" prop="name">
<el-form-item label="活动名称" prop="name" ref="field">
<el-input type="textarea" v-model="form.name"></el-input>
</el-form-item>
</el-form>
@ -262,18 +262,18 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.not.true;
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('请输入活动名称');
expect(field.validateMessage).to.equal('请输入活动名称');
vm.setValue('aaaaa');
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
vm.setValue('aa');
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('请输入活动名称');
expect(field.validateMessage).to.equal('请输入活动名称');
done();
});
});
@ -284,7 +284,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="记住密码" prop="region">
<el-form-item label="记住密码" prop="region" ref="field">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
@ -311,15 +311,15 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.true;
vm.setValue('');
setTimeout(_ => {
expect(fields.region.validateMessage).to.equal('请选择活动区域');
expect(field.validateMessage).to.equal('请选择活动区域');
vm.setValue('shanghai');
setTimeout(_ => {
expect(fields.region.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
done();
}, 100);
}, 100);
@ -329,7 +329,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="记住密码" prop="date">
<el-form-item label="记住密码" prop="date" ref="field">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date" style="width: 100%;"></el-date-picker>
</el-form-item>
</el-form>
@ -353,15 +353,15 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.not.true;
vm.$refs.form.$nextTick(_ => {
expect(fields.date.validateMessage).to.equal('请选择日期');
expect(field.validateMessage).to.equal('请选择日期');
vm.setValue(new Date());
vm.$refs.form.$nextTick(_ => {
expect(fields.date.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
done();
});
});
@ -371,7 +371,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="记住密码" prop="date">
<el-form-item label="记住密码" prop="date" ref="field">
<el-time-picker type="fixed-time" placeholder="选择时间" v-model="form.date" style="width: 100%;"></el-time-picker>
</el-form-item>
</el-form>
@ -395,14 +395,14 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.not.true;
vm.$refs.form.$nextTick(_ => {
expect(fields.date.validateMessage).to.equal('请选择时间');
expect(field.validateMessage).to.equal('请选择时间');
vm.setValue(new Date());
vm.$refs.form.$nextTick(_ => {
expect(fields.date.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
done();
});
});
@ -412,7 +412,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="活动名称" prop="type">
<el-form-item label="活动名称" prop="type" ref="field">
<el-checkbox-group v-model="form.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
@ -441,14 +441,14 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.not.true;
vm.$refs.form.$nextTick(_ => {
expect(fields.type.validateMessage).to.equal('请选择活动类型');
expect(field.validateMessage).to.equal('请选择活动类型');
vm.setValue(['地推活动']);
vm.$refs.form.$nextTick(_ => {
expect(fields.type.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
done();
});
});
@ -458,7 +458,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="活动名称" prop="type">
<el-form-item label="活动名称" prop="type" ref="field">
<el-radio-group v-model="form.type">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
@ -485,14 +485,14 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.not.true;
vm.$refs.form.$nextTick(_ => {
expect(fields.type.validateMessage).to.equal('请选择活动类型');
expect(field.validateMessage).to.equal('请选择活动类型');
vm.setValue('线下场地免费');
vm.$refs.form.$nextTick(_ => {
expect(fields.type.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
done();
});
});
@ -502,7 +502,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="活动名称" prop="name">
<el-form-item label="活动名称" prop="name" ref="field">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
@ -541,7 +541,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="活动名称" prop="name">
<el-form-item label="活动名称" prop="name" ref="field">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
@ -565,14 +565,14 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.not.true;
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('长度至少为5');
expect(field.validateMessage).to.equal('长度至少为5');
vm.setValue('aaaaaa');
vm.$refs.form.$nextTick(_ => {
expect(fields.name.validateMessage).to.equal('');
expect(field.validateMessage).to.equal('');
done();
});
});
@ -582,7 +582,7 @@ describe('Form', () => {
vm = createVue({
template: `
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="活动名称" prop="name" :error="error" ref="formitem">
<el-form-item label="活动名称" prop="name" :error="error" ref="field">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
@ -607,13 +607,13 @@ describe('Form', () => {
}
}, true);
vm.$refs.form.validate(valid => {
let fields = vm.$refs.form.fields;
let field = vm.$refs.field;
expect(valid).to.true;
vm.error = '输入不合法';
vm.$refs.formitem.$nextTick(_ => {
expect(fields.name.validateState).to.equal('error');
expect(fields.name.validateMessage).to.equal('输入不合法');
vm.$refs.field.$nextTick(_ => {
expect(field.validateState).to.equal('error');
expect(field.validateMessage).to.equal('输入不合法');
done();
});
});

View File

@ -65,6 +65,7 @@ describe('Radio', () => {
};
}
}, true);
setTimeout(_ => {
expect(vm.$refs.radio1.$el.querySelector('.is-checked')).to.be.ok;
let radioElm = vm.$refs.radio2.$el;
radioElm.click();
@ -73,8 +74,10 @@ describe('Radio', () => {
expect(vm.radio === 6).to.be.true;
done();
});
}, 50);
});
it('radio button', done => {
describe('Radio', () => {
it('create', done => {
vm = createVue({
template: `
<el-radio-group v-model="radio">
@ -98,4 +101,27 @@ describe('Radio', () => {
done();
});
});
it('custom color', done => {
vm = createVue({
template: `
<el-radio-group v-model="radio" fill="#000" text-color="#ff0">
<el-radio-button :label="3" ref="radio1">备选项</el-radio-button>
<el-radio-button :label="6" ref="radio2">备选项</el-radio-button>
<el-radio-button :label="9">备选项</el-radio-button>
</el-radio-group>
`,
data() {
return {
radio: 3
};
}
}, true);
vm.$nextTick(_ => {
expect(vm.$refs.radio1.activeStyle.backgroundColor).to.equal('#000');
expect(vm.$refs.radio1.activeStyle.borderColor).to.equal('#000');
expect(vm.$refs.radio1.activeStyle.color).to.equal('#ff0');
done();
});
});
});
});

View File

@ -147,6 +147,37 @@ describe('Table', () => {
done();
}, DELAY);
});
it('tableRowStyle[Object]', done => {
const vm = createTable(':row-style="{ height: \'60px\' }"', {});
setTimeout(_ => {
expect(vm.$el.querySelector('.el-table__body tr').style.height).to.equal('60px');
destroyVM(vm);
done();
}, DELAY);
});
it('tableRowStyle[Function]', done => {
const vm = createTable(':row-style="tableRowStyle"', {
methods: {
tableRowStyle(row, index) {
if (index === 1) {
return { height: '60px' };
}
return null;
}
}
});
setTimeout(_ => {
expect(vm.$el.querySelector('.el-table__body tr:nth-child(1)').style.height).to.equal('');
expect(vm.$el.querySelector('.el-table__body tr:nth-child(2)').style.height).to.equal('60px');
destroyVM(vm);
done();
}, DELAY);
});
});
describe('filter', () => {

View File

@ -127,6 +127,21 @@ describe('Tree', () => {
expect(vm.$el.querySelectorAll('.el-tree-node.is-expanded').length).to.equal(2);
});
it('defaultExpandedKeys set', (done) => {
vm = getTreeVm(':props="defaultProps" :default-expanded-keys="defaultExpandedKeys" node-key="id"', {
created() {
this.defaultExpandedKeys = [1, 3];
}
});
expect(vm.$el.querySelectorAll('.el-tree-node.is-expanded').length).to.equal(2);
vm.defaultExpandedKeys = [2];
vm.data = JSON.parse(JSON.stringify(vm.data));
setTimeout(() => {
expect(vm.$el.querySelectorAll('.el-tree-node.is-expanded').length).to.equal(1);
done();
}, 50);
});
it('filter-node-method', (done) => {
vm = getTreeVm(':props="defaultProps" :filter-node-method="filterNode"', {
methods: {