Commit 22fd5f1f authored by 杨奕's avatar 杨奕 Committed by GitHub

Merge pull request #335 from QingWei-Li/unittest

Unittest
parents b66727a3 cd8b9a14
...@@ -9,3 +9,4 @@ lib ...@@ -9,3 +9,4 @@ lib
examples/element-ui examples/element-ui
fe.element/element-ui fe.element/element-ui
.npmrc .npmrc
coverage
sudo: false sudo: false
language: node_js language: node_js
node_js: node_js:
- "5" - 5
script: make dist cache:
bundler: true
directories:
- node_modules # NPM packages
- travis_phantomjs
before_install:
# Upgrade PhantomJS to v2.1.1.
- "export PHANTOMJS_VERSION=2.1.1"
- "export PATH=$PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin:$PATH"
- "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi"
- "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then wget https://github.com/Medium/phantomjs/releases/download/v$PHANTOMJS_VERSION/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2; fi"
- "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi"
- "phantomjs --version"
script:
- "make dist"
- "npm t"
## 更新日志 ## 更新日志
### 1.0.0(待发布) ### 1.0.0-rc.7
*2016-XX-XX* *2016-XX-XX*
- Upload 新增 Data 属性支持额外数据的传输
- DatePicker 修复 `$t` 报错
- Popper 重构 vue-popper
- Pagination 修复输入后再点击切换,输入框的值不更新
- Step: 修复自定义 icon 的样式
- 修复 Tree 组件 checkbox 点击失效的问题
### 1.0.0-rc.6
*2016-10-11*
- 修复 Tabs 切换后 Tab-panel 被销毁的问题 - 修复 Tabs 切换后 Tab-panel 被销毁的问题
- 修复 TimePicker 错误的隐藏面板 - 修复 TimePicker 错误的隐藏面板
- 修复 Table Cell 的样式, #204 - 修复 Table Cell 的样式, #204
...@@ -17,6 +28,9 @@ ...@@ -17,6 +28,9 @@
- 修复 多选可搜索的 Select 下拉选项自动展开的问题 - 修复 多选可搜索的 Select 下拉选项自动展开的问题
- 为 Dialog 添加 top 属性 - 为 Dialog 添加 top 属性
- 修复 Menu 组件垂直模式下开启 router 属性会立刻跳转的问题 #295 - 修复 Menu 组件垂直模式下开启 router 属性会立刻跳转的问题 #295
- Checkbox change 事件现在只能被人为的交互操作所触发
- 新增 Checkbox checked 属性
- 修复 Select 远程搜索时使用键盘选择选项无法更新 v-model 的问题
#### 非兼容性更新 #### 非兼容性更新
......
...@@ -28,3 +28,27 @@ exports.alias = { ...@@ -28,3 +28,27 @@ exports.alias = {
}; };
exports.jsexclude = /node_modules|utils\/popper\.js|utils\/date.\js/; exports.jsexclude = /node_modules|utils\/popper\.js|utils\/date.\js/;
exports.postcss = function(webapck) {
return [
require('postcss-salad')({
browser: ['ie > 8', 'last 2 version'],
features: {
'partialImport': {
addDependencyTo: webapck
},
'bem': {
'shortcuts': {
'component': 'b',
'modifier': 'm',
'descendent': 'e'
},
'separators': {
'descendent': '__',
'modifier': '--'
}
}
}
})
];
};
...@@ -28,29 +28,7 @@ cooking.set({ ...@@ -28,29 +28,7 @@ cooking.set({
sourceMap: true, sourceMap: true,
alias: config.alias, alias: config.alias,
extends: ['vue2', 'lint'], extends: ['vue2', 'lint'],
postcss: function(webapck) { postcss: config.postcss
return [
require('postcss-salad')({
browser: ['ie > 8', 'last 2 version'],
features: {
'partialImport': {
addDependencyTo: webapck
},
'bem': {
'shortcuts': {
'component': 'b',
'modifier': 'm',
'descendent': 'e'
},
'separators': {
'descendent': '__',
'modifier': '--'
}
}
}
})
];
}
}); });
cooking.add('loader.md', { cooking.add('loader.md', {
......
var path = require('path');
var cooking = require('cooking');
var config = require('./config');
var projectRoot = path.resolve(__dirname, '../');
var ProgressBarPlugin = require('progress-bar-webpack-plugin');
cooking.set({
entry: './src/index.js',
extends: ['vue2'],
minimize: false,
alias: config.alias,
postcss: config.postcss,
sourceMap: '#inline-source-map'
});
cooking.add('vue.loaders.js', 'isparta');
cooking.add('loader.js.exclude', config.jsexclude);
cooking.add('preLoader.js', {
test: /\.js$/,
loader: 'isparta-loader',
include: path.resolve(projectRoot, 'src')
});
cooking.add('plugins.process', new ProgressBarPlugin());
module.exports = cooking.resolve();
...@@ -21,15 +21,20 @@ ...@@ -21,15 +21,20 @@
<el-button size="small">回复</el-button> <el-button size="small">回复</el-button>
</el-badge> </el-badge>
<el-dropdown text="点我查看" type="text" :icon-separate="false" trigger="click"> <el-dropdown trigger="click">
<el-dropdown-item class="clearfix"> <span class="el-dropdown-link">
评论 点我查看<i class="el-icon-caret-bottom el-icon-right"></i>
<el-badge class="mark" :value="12" /> </span>
</el-dropdown-item> <el-dropdown-menu slot="dropdown">
<el-dropdown-item class="clearfix"> <el-dropdown-item class="clearfix">
回复 评论
<el-badge class="mark" :value="3" /> <el-badge class="mark" :value="12" />
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item class="clearfix">
回复
<el-badge class="mark" :value="3" />
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> </el-dropdown>
``` ```
::: :::
......
...@@ -4,16 +4,20 @@ ...@@ -4,16 +4,20 @@
return { return {
checkList: ['选中且禁用','复选框 A'], checkList: ['选中且禁用','复选框 A'],
// checkList2: ['复选框 A'], // checkList2: ['复选框 A'],
checked: true, checked: false,
checked1: false, checked1: false,
checked2: true, checked2: true,
isValid: '可用' isValid: '可用'
}; };
},
methods: {
handleChange(ev) {
console.log(ev);
}
} }
}; };
</script> </script>
<style> <style>
.demo-box.demo-checkbox { .demo-box.demo-checkbox {
.checkbox { .checkbox {
...@@ -37,7 +41,7 @@ ...@@ -37,7 +41,7 @@
```html ```html
<template> <template>
<!-- `checked` 为 true 或 false --> <!-- `checked` 为 true 或 false -->
<el-checkbox class="checkbox" v-model="checked">备选项</el-checkbox> <el-checkbox class="checkbox" v-model="checked" checked>备选项</el-checkbox>
</template> </template>
<script> <script>
export default { export default {
...@@ -59,7 +63,7 @@ ...@@ -59,7 +63,7 @@
```html ```html
<template> <template>
<el-checkbox class="checkbox" v-model="checked1" disabled>备选项</el-checkbox> <el-checkbox class="checkbox" v-model="checked1" disabled>备选项1</el-checkbox>
<el-checkbox class="checkbox" v-model="checked2" disabled>备选项</el-checkbox> <el-checkbox class="checkbox" v-model="checked2" disabled>备选项</el-checkbox>
</template> </template>
<script> <script>
...@@ -139,8 +143,10 @@ ...@@ -139,8 +143,10 @@
| true-label | 选中时的值 | string, number | — | — | | true-label | 选中时的值 | string, number | — | — |
| false-label | 没有选中时的值 | string, number | — | — | | false-label | 没有选中时的值 | string, number | — | — |
| disabled | 按钮禁用 | boolean | — | false | | disabled | 按钮禁用 | boolean | — | false |
| checked | 当前是否勾选 | boolean | — | false |
| indeterminate | 设置 indeterminate 状态,只负责样式控制 | boolean | — | false |
### Checkbox-group Events ### Checkbox-group Events
| 事件名称 | 说明 | 回调参数 | | 事件名称 | 说明 | 回调参数 |
|---------- |-------- |---------- | |---------- |-------- |---------- |
| change | 当绑定值变化时触发的事件 | 选中的 Checkbox Label 值 | | change | 当绑定值变化时触发的事件 | event 事件对象 |
...@@ -119,6 +119,7 @@ ...@@ -119,6 +119,7 @@
<span class="demonstration">带快捷选项</span> <span class="demonstration">带快捷选项</span>
<el-date-picker <el-date-picker
v-model="value2" v-model="value2"
align="right"
type="date" type="date"
placeholder="选择日期" placeholder="选择日期"
:picker-options="pickerOptions1"> :picker-options="pickerOptions1">
...@@ -193,6 +194,7 @@ ...@@ -193,6 +194,7 @@
<span class="demonstration"></span> <span class="demonstration"></span>
<el-date-picker <el-date-picker
v-model="value5" v-model="value5"
align="right"
type="year" type="year"
placeholder="选择年"> placeholder="选择年">
</el-date-picker> </el-date-picker>
......
...@@ -25,7 +25,11 @@ npm run bootstrap ...@@ -25,7 +25,11 @@ npm run bootstrap
registry=https://registry.npm.taobao.org registry=https://registry.npm.taobao.org
``` ```
然后再运行 `npm run bootstrap` 安装依赖。 然后再运行
```shell
PHANTOMJS_CDNURL=http://npm.taobao.org/mirrors/phantomjs npm run bootstrap
```
### 启动开发环境 ### 启动开发环境
......
...@@ -152,7 +152,8 @@ ...@@ -152,7 +152,8 @@
### Attributes ### Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
|------------- |---------------- |---------------- |---------------------- |-------- | |------------- |---------------- |---------------- |---------------------- |-------- |
| type | 菜单按钮类型,同 Button 组件 | string | — | — | | type | 菜单按钮类型,同 Button 组件(只在`split-button`为 true 的情况下有效) | string | — | — |
| size | 菜单按钮尺寸,同 Button 组件(只在`split-button`为 true 的情况下有效) | string | hover, click | hover |
| split-button | 下拉触发元素呈现为按钮组 | boolean | — | false | | split-button | 下拉触发元素呈现为按钮组 | boolean | — | false |
| menu-align | 菜单水平对齐方向 | string | start, end | end | | menu-align | 菜单水平对齐方向 | string | start, end | end |
| trigger | 触发下拉的行为 | string | hover, click | hover | | trigger | 触发下拉的行为 | string | hover, click | hover |
......
...@@ -514,7 +514,7 @@ ...@@ -514,7 +514,7 @@
<el-option label="区域二" value="beijing"></el-option> <el-option label="区域二" value="beijing"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="活动时间"> <el-form-item label="活动时间" required>
<el-col :span="11"> <el-col :span="11">
<el-form-item prop="date1"> <el-form-item prop="date1">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker> <el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
......
...@@ -627,7 +627,7 @@ ...@@ -627,7 +627,7 @@
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
|------------- |---------------- |---------------- |---------------------- |-------- | |------------- |---------------- |---------------- |---------------------- |-------- |
| type | 同原生的 input 的 type 属性,另外提供 type="textarea" | string | — | — | | type | 类型 | string | text/textarea | text |
| value | 绑定值 | string, number | — | — | | value | 绑定值 | string, number | — | — |
| maxlength | 最大输入长度 | number | — | — | | maxlength | 最大输入长度 | number | — | — |
| minlength | 最小输入长度 | number | — | — | | minlength | 最小输入长度 | number | — | — |
......
...@@ -16,22 +16,22 @@ ...@@ -16,22 +16,22 @@
.demo-box.demo-slider .source { .demo-box.demo-slider .source {
padding: 0; padding: 0;
} }
.demo-box.demo-slider .block { .demo-box.demo-slider .block {
padding: 30px 24px; padding: 30px 24px;
overflow: hidden; overflow: hidden;
border-bottom: solid 1px #EFF2F6; border-bottom: solid 1px #EFF2F6;
&:last-child { &:last-child {
border-bottom: none; border-bottom: none;
} }
} }
.demo-box.demo-slider .demonstration { .demo-box.demo-slider .demonstration {
font-size: 14px; font-size: 14px;
color: #8492a6; color: #8492a6;
line-height: 44px; line-height: 44px;
} }
.demo-box.demo-slider .demonstration + .el-slider { .demo-box.demo-slider .demonstration + .el-slider {
float: right; float: right;
width: 70%; width: 70%;
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<template> <template>
<div class="block"> <div class="block">
<span class="demonstration">默认</span> <span class="demonstration">默认</span>
<el-slider v-model="value1"></el-slider> <el-slider v-model="value1"></el-slider>
</div> </div>
<div class="block"> <div class="block">
<span class="demonstration">自定义初始值</span> <span class="demonstration">自定义初始值</span>
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
<el-slider <el-slider
v-model="value3" v-model="value3"
:step="10"> :step="10">
</el-slider> </el-slider>
</div> </div>
<div class="block"> <div class="block">
<span class="demonstration">显示间断点</span> <span class="demonstration">显示间断点</span>
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
<el-slider <el-slider
v-model="value5" v-model="value5"
show-input> show-input>
</el-slider> </el-slider>
</div> </div>
</template> </template>
......
{ {
"name": "element-ui", "name": "element-ui",
"version": "1.0.0-rc.5", "version": "1.0.0-rc.6",
"description": "A Component Library for Vue.js.", "description": "A Component Library for Vue.js.",
"main": "lib/element-ui.common.js", "main": "lib/element-ui.common.js",
"files": [ "files": [
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
"pub:all": "npm run dist:all && lerna publish", "pub:all": "npm run dist:all && lerna publish",
"build:utils": "babel src/utils --out-dir lib/utils", "build:utils": "babel src/utils --out-dir lib/utils",
"clean": "rimraf lib && rimraf packages/*/lib", "clean": "rimraf lib && rimraf packages/*/lib",
"lint": "eslint src/**/*.js packages/**/*.{js,vue} build/**/*.js --quiet" "lint": "eslint src/**/*.js test/**/*.js packages/**/*.{js,vue} build/**/*.js --quiet",
"test:watch": "karma start test/unit/karma.conf.js",
"test": "karma start test/unit/karma.conf.js --single-run"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
...@@ -43,6 +45,7 @@ ...@@ -43,6 +45,7 @@
"babel-plugin-syntax-jsx": "^6.8.0", "babel-plugin-syntax-jsx": "^6.8.0",
"babel-plugin-transform-vue-jsx": "^3.1.0", "babel-plugin-transform-vue-jsx": "^3.1.0",
"babel-preset-es2015": "^6.14.0", "babel-preset-es2015": "^6.14.0",
"chai": "^3.5.0",
"cheerio": "^0.18.0", "cheerio": "^0.18.0",
"cooking": "^1.1.0", "cooking": "^1.1.0",
"cooking-lint": "^0.1.3", "cooking-lint": "^0.1.3",
...@@ -57,24 +60,39 @@ ...@@ -57,24 +60,39 @@
"highlight.js": "^9.3.0", "highlight.js": "^9.3.0",
"html-loader": "^0.4.3", "html-loader": "^0.4.3",
"html-webpack-plugin": "^2.22.0", "html-webpack-plugin": "^2.22.0",
"inject-loader": "^3.0.0-beta2",
"isparta-loader": "^2.0.0",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"json-templater": "^1.0.4", "json-templater": "^1.0.4",
"karma": "^1.3.0",
"karma-coverage": "^1.1.1",
"karma-mocha": "^1.2.0",
"karma-phantomjs-launcher": "^1.0.2",
"karma-sinon-chai": "^1.2.4",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.26",
"karma-webpack": "^1.8.0",
"lerna": "2.0.0-beta.18", "lerna": "2.0.0-beta.18",
"lolex": "^1.5.1",
"markdown-it": "^6.1.1", "markdown-it": "^6.1.1",
"markdown-it-container": "^2.0.0", "markdown-it-container": "^2.0.0",
"mocha": "^3.1.1",
"object-assign": "^4.1.0", "object-assign": "^4.1.0",
"phantomjs-prebuilt": "^2.1.13",
"postcss": "^5.1.2", "postcss": "^5.1.2",
"postcss-loader": "^0.11.1", "postcss-loader": "^0.11.1",
"postcss-salad": "^1.0.5", "postcss-salad": "^1.0.5",
"rimraf": "^2.5.4", "rimraf": "^2.5.4",
"sinon": "^1.17.6",
"sinon-chai": "^2.8.0",
"style-loader": "^0.13.1", "style-loader": "^0.13.1",
"theaterjs": "^3.0.0", "theaterjs": "^3.0.0",
"uppercamelcase": "^1.1.0", "uppercamelcase": "^1.1.0",
"url-loader": "^0.5.7", "url-loader": "^0.5.7",
"vue": "^2.0.1", "vue": "^2.0.2",
"vue-loader": "^9.5.1", "vue-loader": "^9.5.1",
"vue-markdown-loader": "^0.5.1", "vue-markdown-loader": "^0.5.1",
"vue-popup": "^0.2.6", "vue-popup": "^0.2.8",
"vue-router": "^2.0.0", "vue-router": "^2.0.0",
"webpack": "^1.13.2", "webpack": "^1.13.2",
"webpack-dev-server": "^1.15.1", "webpack-dev-server": "^1.15.1",
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
:disabled="disabled" :disabled="disabled"
:placeholder="placeholder" :placeholder="placeholder"
:name='name' :name='name'
@onchange="handleChange" @change="handleChange"
@onfocus="handleFocus" @focus="handleFocus"
@keydown.up.native="highlight(highlightedIndex - 1)" @keydown.up.native="highlight(highlightedIndex - 1)"
@keydown.down.native="highlight(highlightedIndex + 1)" @keydown.down.native="highlight(highlightedIndex + 1)"
@keydown.enter.native="select(highlightedIndex)" @keydown.enter.native="select(highlightedIndex)"
......
/**
* button
* @module components/basic/menu
* @desc 用于按钮组
* @param {string} label - 名称
*/
export default {
name: 'ElButtonGroup',
functional: true,
render(h, { slots, data }) {
return (
<div
class="el-button-group"
{ ...data }
{ ...{ on: data.nativeOn } }>
{ slots().default }
</div>
);
}
};
<template>
<div class="el-button-group">
<slot></slot>
</div>
</template>
<script>
/**
* button
* @module components/basic/menu
* @desc 用于按钮组
* @param {string} label - 名称
*/
export default {
name: 'ElButtonGroup'
};
</script>
export default {
name: 'ElButton',
functional: true,
props: {
type: {
type: String,
default: 'default'
},
size: String,
icon: {
type: String,
default: ''
},
nativeType: {
type: String,
default: 'button'
},
loading: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
plain: {
type: Boolean,
default: false
}
},
render(h, { props, slots, data }) {
return (
<button
disabled={ props.disabled }
type={ props.nativeType }
class={[
'el-button',
props.type ? 'el-button-' + props.type : '',
props.size ? 'el-button-' + props.size : '',
{
'is-disabled': props.disabled,
'is-loading': props.loading,
'is-plain': props.plain
}
]}
{ ...data }
{ ...{ on: data.nativeOn } }>
{
[
props.loading
? <i class="el-icon-loading"></i>
: {},
props.icon && !props.loading
? <i class={ 'el-icon-' + props.icon }></i>
: {}
]
}
{ slots().default }
</button>
);
}
};
<template>
<button :disabled="disabled" class="el-button"
:type="nativeType"
:class="[
type ? 'el-button-' + type : '',
size ? 'el-button-' + size : '',
{
'is-disabled': disabled,
'is-loading': loading,
'is-plain': plain
}
]"
>
<i class="el-icon-loading" v-if="loading"></i>
<i :class="'el-icon-' + icon" v-if="icon && !loading"></i>
<slot></slot>
</button>
</template>
<script>
/**
* button
*/
export default {
name: 'ElButton',
props: {
type: {
type: String,
default: 'default'
},
size: String,
icon: {
type: String,
default: ''
},
nativeType: {
type: String,
default: 'button'
},
loading: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
plain: {
type: Boolean,
default: false
}
}
};
</script>
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<span class="el-checkbox__inner" <span class="el-checkbox__inner"
:class="{ :class="{
'is-disabled': disabled, 'is-disabled': disabled,
'is-checked': checked, 'is-checked': isChecked,
'is-indeterminate': indeterminate, 'is-indeterminate': indeterminate,
'is-focus': focus 'is-focus': focus
}" }"
...@@ -12,23 +12,25 @@ ...@@ -12,23 +12,25 @@
<input <input
v-if="trueLabel || falseLabel" v-if="trueLabel || falseLabel"
class="el-checkbox__original" class="el-checkbox__original"
type="checkbox"
:disabled="disabled"
:true-value="trueLabel" :true-value="trueLabel"
:false-value="falseLabel" :false-value="falseLabel"
v-model="_value" v-model="_value"
type="checkbox"
@focus="focus = true" @focus="focus = true"
@blur="focus = false" @blur="focus = false"
:disabled="disabled" @change="handleChange"
ref="checkbox"> ref="checkbox">
<input <input
v-else v-else
class="el-checkbox__original" class="el-checkbox__original"
type="checkbox"
:disabled="disabled"
:value="label" :value="label"
v-model="_value" v-model="_value"
@focus="focus = true" @focus="focus = true"
@blur="focus = false" @blur="focus = false"
type="checkbox" @change="handleChange">
:disabled="disabled">
</span> </span>
<span class="el-checkbox__label" v-if="$slots.default || label"> <span class="el-checkbox__label" v-if="$slots.default || label">
<slot></slot> <slot></slot>
...@@ -46,11 +48,10 @@ ...@@ -46,11 +48,10 @@
props: { props: {
value: {}, value: {},
label: { label: String,
type: String
},
indeterminate: Boolean, indeterminate: Boolean,
disabled: Boolean, disabled: Boolean,
checked: Boolean,
trueLabel: [String, Number], trueLabel: [String, Number],
falseLabel: [String, Number] falseLabel: [String, Number]
}, },
...@@ -58,17 +59,17 @@ ...@@ -58,17 +59,17 @@
computed: { computed: {
_value: { _value: {
get() { get() {
return this.value !== undefined ? this.value : this.$parent.value; return !this.wrapInGroup ? this.value : this.$parent.value;
}, },
set(newValue) { set(newValue) {
if (this.value !== undefined) { if (!this.wrapInGroup) {
this.$emit('input', newValue); this.$emit('input', newValue);
} else { } else {
this.$parent.$emit('input', newValue); this.$parent.$emit('input', newValue);
} }
} }
}, },
checked() { isChecked() {
var type = Object.prototype.toString.call(this._value); var type = Object.prototype.toString.call(this._value);
if (type === '[object Boolean]') { if (type === '[object Boolean]') {
...@@ -83,13 +84,30 @@ ...@@ -83,13 +84,30 @@
data() { data() {
return { return {
focus: false focus: false,
wrapInGroup: this.$parent.$options._componentTag === 'el-checkbox-group'
}; };
}, },
watch: { watch: {
checked(sure) { checked: {
this.$emit('change', sure); 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);
} }
} }
}; };
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
<td <td
v-for="cell in row" v-for="cell in row"
:class="getCellClasses(cell)" :class="getCellClasses(cell)"
v-text="cell.type === 'today' ? '今天' : cell.text"></td> v-text="cell.type === 'today' ? $t('datepicker.today') : cell.text"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -214,7 +214,9 @@ ...@@ -214,7 +214,9 @@
}, },
methods: { methods: {
$t: $t, $t(...args) {
return $t.apply(this, args);
},
getCellClasses(cell) { getCellClasses(cell) {
const selectionMode = this.selectionMode; const selectionMode = this.selectionMode;
......
...@@ -58,7 +58,9 @@ ...@@ -58,7 +58,9 @@
}, },
methods: { methods: {
$t: $t, $t(...args) {
return $t.apply(this, args);
},
handleMonthTableClick(event) { handleMonthTableClick(event) {
const target = event.target; const target = event.target;
......
...@@ -3,7 +3,19 @@ ...@@ -3,7 +3,19 @@
@component-namespace el { @component-namespace el {
@b date-picker { @b date-picker {
min-width: 300px; min-width: 254px;
&.has-sidebar.has-time {
min-width: 434px;
}
&.has-sidebar {
min-width: 370px;
}
&.has-time {
min-width: 324px;
}
.el-picker-panel__content { .el-picker-panel__content {
min-width: 224px; min-width: 224px;
......
...@@ -2,6 +2,20 @@ ...@@ -2,6 +2,20 @@
@component-namespace el { @component-namespace el {
@b date-range-picker { @b date-range-picker {
min-width: 520px;
&.has-sidebar.has-time {
min-width: 766px;
}
&.has-sidebar {
min-width: 620px;
}
&.has-time {
min-width: 660px;
}
table { table {
table-layout: fixed; table-layout: fixed;
width: 100%; width: 100%;
......
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
cursor: pointer; cursor: pointer;
background-color: transparent; background-color: transparent;
outline: none; outline: none;
font-size: 12px;
&[disabled] { &[disabled] {
color: #cccccc; color: #cccccc;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
@component-namespace el { @component-namespace el {
@b time-range-picker { @b time-range-picker {
width: 354px; min-width: 354px;
overflow: visible; overflow: visible;
@e content { @e content {
......
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
class="el-picker-panel el-date-range-picker"> :style="{ width: width + 'px' }"
class="el-picker-panel el-date-range-picker"
:class="{
'has-sidebar': $slots.sidebar || shortcuts,
'has-time': showTime
}">
<div class="el-picker-panel__body-wrapper"> <div class="el-picker-panel__body-wrapper">
<slot name="sidebar" class="el-picker-panel__sidebar"></slot> <slot name="sidebar" class="el-picker-panel__sidebar"></slot>
<div class="el-picker-panel__sidebar" v-if="shortcuts"> <div class="el-picker-panel__sidebar" v-if="shortcuts">
...@@ -31,6 +36,7 @@ ...@@ -31,6 +36,7 @@
@focus="leftTimePickerVisible = true" @focus="leftTimePickerVisible = true"
@change="handleTimeChange($event, 'min')"/> @change="handleTimeChange($event, 'min')"/>
<time-picker <time-picker
:picker-width="leftPickerWidth"
ref="lefttimepicker" ref="lefttimepicker"
:date="minDate" :date="minDate"
@pick="handleLeftTimePick" @pick="handleLeftTimePick"
...@@ -41,6 +47,7 @@ ...@@ -41,6 +47,7 @@
<span class="el-icon-arrow-right"></span> <span class="el-icon-arrow-right"></span>
<span class="el-date-range-picker__editors-wrap is-right"> <span class="el-date-range-picker__editors-wrap is-right">
<input <input
ref="leftInput"
placeholder="结束日期" placeholder="结束日期"
class="el-date-range-picker__editor" class="el-date-range-picker__editor"
v-model="rightVisibleDate" v-model="rightVisibleDate"
...@@ -51,6 +58,7 @@ ...@@ -51,6 +58,7 @@
class="el-date-range-picker__time-picker-wrap" class="el-date-range-picker__time-picker-wrap"
v-clickoutside="closeRightTimePicker"> v-clickoutside="closeRightTimePicker">
<input <input
ref="rightInput"
placeholder="结束时间" placeholder="结束时间"
class="el-date-range-picker__editor" class="el-date-range-picker__editor"
v-model="rightVisibleTime" v-model="rightVisibleTime"
...@@ -58,6 +66,7 @@ ...@@ -58,6 +66,7 @@
:readonly="!minDate" :readonly="!minDate"
@change="handleTimeChange($event, 'max')" /> @change="handleTimeChange($event, 'max')" />
<time-picker <time-picker
:picker-width="rightPickerWidth"
ref="righttimepicker" ref="righttimepicker"
:date="maxDate" :date="maxDate"
@pick="handleRightTimePick" @pick="handleRightTimePick"
...@@ -119,12 +128,12 @@ ...@@ -119,12 +128,12 @@
<div class="el-picker-panel__footer" v-if="showTime"> <div class="el-picker-panel__footer" v-if="showTime">
<!-- <a <!-- <a
class="el-picker-panel__link-btn" class="el-picker-panel__link-btn"
@click="changeToToday">{{ $t('datepicker.today') }}</a> --> @click="changeToToday">{{ $t('datepicker.now') }}</a> -->
<button <button
type="button" type="button"
class="el-picker-panel__btn" class="el-picker-panel__btn"
@click="handleConfirm" @click="handleConfirm"
:disabled="btnDisabled">确定</button> :disabled="btnDisabled">{{ $t('datepicker.confirm') }}</button>
</div> </div>
</div> </div>
</transition> </transition>
...@@ -140,11 +149,11 @@ ...@@ -140,11 +149,11 @@
}, },
leftLabel() { leftLabel() {
return this.date.getFullYear() + '' + (this.date.getMonth() + 1) + ''; return this.date.getFullYear() + ' ' + this.$t('datepicker.month') + ' ' + (this.date.getMonth() + 1) + ' ' + this.$t('datepicker.month');
}, },
rightLabel() { rightLabel() {
return this.rightDate.getFullYear() + '' + (this.rightDate.getMonth() + 1) + ''; return this.rightDate.getFullYear() + ' ' + this.$t('datepicker.month') + ' ' + (this.rightDate.getMonth() + 1) + ' ' + this.$t('datepicker.month');
}, },
leftYear() { leftYear() {
...@@ -254,6 +263,8 @@ ...@@ -254,6 +263,8 @@
data() { data() {
return { return {
leftPickerWidth: 0,
rightPickerWidth: 0,
date: new Date(), date: new Date(),
minDate: '', minDate: '',
maxDate: '', maxDate: '',
...@@ -269,11 +280,26 @@ ...@@ -269,11 +280,26 @@
visible: '', visible: '',
disabledDate: '', disabledDate: '',
leftTimePickerVisible: false, leftTimePickerVisible: false,
rightTimePickerVisible: false rightTimePickerVisible: false,
width: 0
}; };
}, },
watch: { watch: {
showTime(val) {
if (!val) return;
this.$nextTick(_ => {
const leftInputElm = this.$refs.leftInput;
const rightInputElm = this.$refs.rightInput;
if (leftInputElm) {
this.leftPickerWidth = leftInputElm.getBoundingClientRect().width + 10;
}
if (rightInputElm) {
this.rightPickerWidth = rightInputElm.getBoundingClientRect().width + 10;
}
});
},
minDate() { minDate() {
this.$nextTick(() => { this.$nextTick(() => {
if (this.maxDate && this.maxDate < this.minDate) { if (this.maxDate && this.maxDate < this.minDate) {
...@@ -302,7 +328,9 @@ ...@@ -302,7 +328,9 @@
}, },
methods: { methods: {
$t, $t(...args) {
return $t.apply(this, args);
},
closeLeftTimePicker() { closeLeftTimePicker() {
this.leftTimePickerVisible = false; this.leftTimePickerVisible = false;
......
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
class="el-picker-panel el-date-picker"> :style="{
width: width + 'px'
}"
class="el-picker-panel el-date-picker"
:class="{
'has-sidebar': $slots.sidebar || shortcuts,
'has-time': showTime
}">
<div class="el-picker-panel__body-wrapper"> <div class="el-picker-panel__body-wrapper">
<slot name="sidebar" class="el-picker-panel__sidebar"></slot> <slot name="sidebar" class="el-picker-panel__sidebar"></slot>
<div class="el-picker-panel__sidebar" v-if="shortcuts"> <div class="el-picker-panel__sidebar" v-if="shortcuts">
...@@ -15,20 +22,22 @@ ...@@ -15,20 +22,22 @@
<div class="el-picker-panel__body"> <div class="el-picker-panel__body">
<div class="el-date-picker__time-header" v-if="showTime"> <div class="el-date-picker__time-header" v-if="showTime">
<input <input
placehoder="选择日期" :placehoder="$t('datepicker.selectDate')"
type="text" type="text"
v-model="visibleDate" v-model="visibleDate"
class="el-date-picker__editor"> class="el-date-picker__editor">
<span style="position: relative" v-clickoutside="closeTimePicker"> <span style="position: relative" v-clickoutside="closeTimePicker">
<input <input
ref="input"
@focus="timePickerVisible = true" @focus="timePickerVisible = true"
v-model="visibleTime" v-model="visibleTime"
placehoder="选择时间" :placehoder="$t('datepicker.selectTime')"
type="text" type="text"
class="el-date-picker__editor"> class="el-date-picker__editor">
<time-picker <time-picker
ref="timepicker" ref="timepicker"
:date="date" :date="date"
:picker-width="pickerWidth"
@pick="handleTimePick" @pick="handleTimePick"
:visible="timePickerVisible"> :visible="timePickerVisible">
</time-picker> </time-picker>
...@@ -53,7 +62,7 @@ ...@@ -53,7 +62,7 @@
@click="showMonthPicker" @click="showMonthPicker"
v-show="currentView === 'date'" v-show="currentView === 'date'"
class="el-date-picker__header-label" class="el-date-picker__header-label"
:class="{ active: currentView === 'month' }">{{ month + 1 }}</span> :class="{ active: currentView === 'month' }">{{ month + 1 }} {{$t('datepicker.month')}}</span>
<button <button
type="button" type="button"
@click="nextYear" @click="nextYear"
...@@ -100,7 +109,7 @@ ...@@ -100,7 +109,7 @@
<a <a
href="JavaScript:" href="JavaScript:"
class="el-picker-panel__link-btn" class="el-picker-panel__link-btn"
@click="changeToToday">{{ $t('datepicker.today') }}</a> @click="changeToToday">{{ $t('datepicker.now') }}</a>
<button <button
type="button" type="button"
class="el-picker-panel__btn" class="el-picker-panel__btn"
...@@ -115,6 +124,16 @@ ...@@ -115,6 +124,16 @@
export default { export default {
watch: { watch: {
showTime(val) {
if (!val) return;
this.$nextTick(_ => {
const inputElm = this.$refs.input;
if (inputElm) {
this.pickerWidth = inputElm.getBoundingClientRect().width + 10;
}
});
},
value(newVal) { value(newVal) {
if (this.selectionMode === 'day' && newVal instanceof Date) { if (this.selectionMode === 'day' && newVal instanceof Date) {
this.date = newVal; this.date = newVal;
...@@ -148,7 +167,9 @@ ...@@ -148,7 +167,9 @@
}, },
methods: { methods: {
$t: $t, $t(...args) {
return $t.apply(this, args);
},
resetDate() { resetDate() {
this.date = new Date(this.date); this.date = new Date(this.date);
...@@ -326,6 +347,7 @@ ...@@ -326,6 +347,7 @@
data() { data() {
return { return {
pickerWidth: 0,
date: new Date(), date: new Date(),
value: '', value: '',
showTime: false, showTime: false,
...@@ -337,7 +359,8 @@ ...@@ -337,7 +359,8 @@
year: null, year: null,
month: null, month: null,
week: null, week: null,
timePickerVisible: false timePickerVisible: false,
width: 0
}; };
}, },
...@@ -383,11 +406,12 @@ ...@@ -383,11 +406,12 @@
yearLabel() { yearLabel() {
const year = this.year; const year = this.year;
if (!year) return ''; if (!year) return '';
const yearTranslation = this.$t('datepicker.year');
if (this.currentView === 'year') { if (this.currentView === 'year') {
const startYear = Math.floor(year / 10) * 10; const startYear = Math.floor(year / 10) * 10;
return startYear + '' + '-' + (startYear + 9) + ''; return startYear + ' ' + yearTranslation + '-' + (startYear + 9) + ' ' + yearTranslation;
} }
return this.year + ''; return this.year + ' ' + yearTranslation;
}, },
hours: { hours: {
......
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
:style="{ width: width + 'px' }"
class="el-time-range-picker el-picker-panel"> class="el-time-range-picker el-picker-panel">
<div class="el-time-range-picker__content"> <div class="el-time-range-picker__content">
<div class="el-time-range-picker__cell"> <div class="el-time-range-picker__cell">
<div class="el-time-range-picker__header">开始时间</div> <div class="el-time-range-picker__header">{{ $t('datepicker.startTime') }}</div>
<div class="el-time-range-picker__body el-time-panel__content"> <div class="el-time-range-picker__body el-time-panel__content">
<time-spinner <time-spinner
ref="minSpinner" ref="minSpinner"
...@@ -19,7 +20,7 @@ ...@@ -19,7 +20,7 @@
</div> </div>
</div> </div>
<div class="el-time-range-picker__cell"> <div class="el-time-range-picker__cell">
<div class="el-time-range-picker__header">结束时间</div> <div class="el-time-range-picker__header">{{ $t('datepicker.endTime') }}</div>
<div class="el-time-range-picker__body el-time-panel__content"> <div class="el-time-range-picker__body el-time-panel__content">
<time-spinner <time-spinner
ref="maxSpinner" ref="maxSpinner"
...@@ -37,19 +38,20 @@ ...@@ -37,19 +38,20 @@
<button <button
type="button" type="button"
class="el-time-panel__btn cancel" class="el-time-panel__btn cancel"
@click="handleCancel()">取消</button> @click="handleCancel()">{{ $t('datepicker.cancel') }}</button>
<button <button
type="button" type="button"
class="el-time-panel__btn confirm" class="el-time-panel__btn confirm"
@click="handleConfirm()" @click="handleConfirm()"
:disabled="btnDisabled">确定</button> :disabled="btnDisabled">{{ $t('datepicker.confirm') }}</button>
</div> </div>
</div> </div>
</transition> </transition>
</template> </template>
<script type="text/ecmascript-6"> <script type="text/babel">
import { parseDate, limitRange } from '../util'; import { parseDate, limitRange } from '../util';
import { $t } from '../util';
const MIN_TIME = parseDate('00:00:00', 'HH:mm:ss'); const MIN_TIME = parseDate('00:00:00', 'HH:mm:ss');
const MAX_TIME = parseDate('23:59:59', 'HH:mm:ss'); const MAX_TIME = parseDate('23:59:59', 'HH:mm:ss');
...@@ -90,11 +92,16 @@ ...@@ -90,11 +92,16 @@
minMinutes: minTime.getMinutes(), minMinutes: minTime.getMinutes(),
minSeconds: minTime.getSeconds(), minSeconds: minTime.getSeconds(),
format: 'HH:mm:ss', format: 'HH:mm:ss',
visible: false visible: false,
width: 0
}; };
}, },
methods: { methods: {
$t(...args) {
return $t.apply(this, args);
},
handleCancel() { handleCancel() {
this.$emit('pick'); this.$emit('pick');
}, },
......
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="visible" v-show="visible"
:style="{ width: width + 'px' }"
class="el-picker-panel time-select"> class="el-picker-panel time-select">
<div class="el-picker-panel__content"> <div class="el-picker-panel__content">
<div class="time-select-item" <div class="time-select-item"
...@@ -16,7 +17,7 @@ ...@@ -16,7 +17,7 @@
</transition> </transition>
</template> </template>
<script type="text/ecmascript-6"> <script type="text/babel">
const parseTime = function(time) { const parseTime = function(time) {
const values = ('' || time).split(':'); const values = ('' || time).split(':');
if (values.length >= 2) { if (values.length >= 2) {
...@@ -91,7 +92,8 @@ ...@@ -91,7 +92,8 @@
step: '00:30', step: '00:30',
value: '', value: '',
visible: false, visible: false,
minTime: '' minTime: '',
width: 0
}; };
}, },
......
<template> <template>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="$emit('dodestroy')">
<div <div
v-show="currentVisible" v-show="currentVisible"
:style="{width: width + 'px'}"
class="el-time-panel"> class="el-time-panel">
<div class="el-time-panel__content"> <div class="el-time-panel__content">
<time-spinner <time-spinner
...@@ -18,11 +19,11 @@ ...@@ -18,11 +19,11 @@
<button <button
type="button" type="button"
class="el-time-panel__btn cancel" class="el-time-panel__btn cancel"
@click="handleCancel()">取消</button> @click="handleCancel()">{{ $t('datepicker.cancel') }}</button>
<button <button
type="button" type="button"
class="el-time-panel__btn confirm" class="el-time-panel__btn confirm"
@click="handleConfirm()">确定</button> @click="handleConfirm()">{{ $t('datepicker.confirm') }}</button>
</div> </div>
</div> </div>
</transition> </transition>
...@@ -31,6 +32,7 @@ ...@@ -31,6 +32,7 @@
<script type="text/babel"> <script type="text/babel">
import { limitRange } from '../util'; import { limitRange } from '../util';
import Vue from 'vue'; import Vue from 'vue';
import { $t } from '../util';
export default { export default {
components: { components: {
...@@ -38,12 +40,12 @@ ...@@ -38,12 +40,12 @@
}, },
props: { props: {
pickerWidth: {},
date: { date: {
default() { default() {
return new Date(); return new Date();
} }
}, },
visible: Boolean visible: Boolean
}, },
...@@ -52,6 +54,10 @@ ...@@ -52,6 +54,10 @@
this.currentVisible = val; this.currentVisible = val;
}, },
pickerWidth(val) {
this.width = val;
},
value(newVal) { value(newVal) {
let date; let date;
if (newVal instanceof Date) { if (newVal instanceof Date) {
...@@ -80,7 +86,8 @@ ...@@ -80,7 +86,8 @@
seconds: 0, seconds: 0,
selectableRange: [], selectableRange: [],
currentDate: this.$options.defaultValue || this.date, currentDate: this.$options.defaultValue || this.date,
currentVisible: this.visible currentVisible: this.visible,
width: this.pickerWidth || 0
}; };
}, },
...@@ -91,6 +98,10 @@ ...@@ -91,6 +98,10 @@
}, },
methods: { methods: {
$t(...args) {
return $t.apply(this, args);
},
handleCancel() { handleCancel() {
this.$emit('pick', null); this.$emit('pick', null);
}, },
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<input <input
class="el-date-editor__editor" class="el-date-editor__editor"
:readonly="readonly" :readonly="readonly"
:type="editorType" type="text"
:placeholder="placeholder" :placeholder="placeholder"
@focus="handleFocus" @focus="handleFocus"
@blur="handleBlur" @blur="handleBlur"
...@@ -33,9 +33,20 @@ ...@@ -33,9 +33,20 @@
import Vue from 'vue'; import Vue from 'vue';
import Clickoutside from 'main/utils/clickoutside'; import Clickoutside from 'main/utils/clickoutside';
import { merge, formatDate, parseDate, getWeekNumber } from './util'; import { merge, formatDate, parseDate, getWeekNumber } from './util';
import Popper from 'main/utils/popper'; import Popper from 'main/utils/vue-popper';
import emitter from 'main/mixins/emitter'; import emitter from 'main/mixins/emitter';
const newPopper = {
props: {
appendToBody: Popper.props.appendToBody,
offset: Popper.props.offset,
boundariesPadding: Popper.props.boundariesPadding
},
methods: Popper.methods,
data: Popper.data,
beforeDestroy: Popper.beforeDestroy
};
const FUNCTION_KEYS = [13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40]; const FUNCTION_KEYS = [13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40];
const RANGE_SEPARATOR = ' - '; const RANGE_SEPARATOR = ' - ';
const DEFAULT_FORMATS = { const DEFAULT_FORMATS = {
...@@ -184,7 +195,7 @@ const PLACEMENT_MAP = { ...@@ -184,7 +195,7 @@ const PLACEMENT_MAP = {
}; };
export default { export default {
mixins: [emitter], mixins: [emitter, newPopper],
props: { props: {
format: String, format: String,
...@@ -274,13 +285,18 @@ export default { ...@@ -274,13 +285,18 @@ export default {
} }
this.$emit('input', value); this.$emit('input', value);
} }
},
editorType() {
return 'text';
} }
}, },
created() {
// vue-popper
this.options = {
boundariesPadding: 0,
gpuAcceleration: false
};
this.placement = PLACEMENT_MAP[this.align] || PLACEMENT_MAP.left;
},
methods: { methods: {
handleClose() { handleClose() {
this.pickerVisible = false; this.pickerVisible = false;
...@@ -386,16 +402,6 @@ export default { ...@@ -386,16 +402,6 @@ export default {
!this.pickerVisible ? this.showPicker() : this.hidePicker(); !this.pickerVisible ? this.showPicker() : this.hidePicker();
}, },
destroyPopper() {
if (this.popper) {
this.resetTransformOrigin(this.popper);
setTimeout(() => {
this.popper && this.popper.destroy();
this.popper = null;
}, 300);
}
},
hidePicker() { hidePicker() {
if (this.picker) { if (this.picker) {
this.picker.resetView && this.picker.resetView(); this.picker.resetView && this.picker.resetView();
...@@ -410,6 +416,8 @@ export default { ...@@ -410,6 +416,8 @@ export default {
this.picker = new Vue(merge({ this.picker = new Vue(merge({
el: document.createElement('div') el: document.createElement('div')
}, this.panel)); }, this.panel));
this.popperElm = this.picker.$el;
this.picker.width = this.$refs.reference.getBoundingClientRect().width;
this.picker.showTime = this.type === 'datetime' || this.type === 'datetimerange'; this.picker.showTime = this.type === 'datetime' || this.type === 'datetimerange';
this.picker.selectionMode = this.selectionMode; this.picker.selectionMode = this.selectionMode;
if (this.format) { if (this.format) {
...@@ -445,6 +453,7 @@ export default { ...@@ -445,6 +453,7 @@ export default {
this.pickerVisible = this.picker.visible = true; this.pickerVisible = this.picker.visible = true;
this.picker.resetView && this.picker.resetView(); this.picker.resetView && this.picker.resetView();
this.picker.$on('dodestroy', this.doDestroy);
this.picker.$on('pick', (date, visible = false) => { this.picker.$on('pick', (date, visible = false) => {
this.$emit('input', date); this.$emit('input', date);
...@@ -464,20 +473,7 @@ export default { ...@@ -464,20 +473,7 @@ export default {
this.pickerVisible = this.picker.visible = true; this.pickerVisible = this.picker.visible = true;
} }
this.$nextTick(() => { this.updatePopper();
if (this.popper) return;
this.popper = new Popper(this.$refs.reference, this.picker.$el, {
gpuAcceleration: false,
placement: PLACEMENT_MAP[this.align] || PLACEMENT_MAP.left,
boundariesPadding: 0,
forceAbsolute: true
});
this.popper.onCreate(popper => {
this.resetTransformOrigin(popper);
});
});
if (this.value instanceof Date) { if (this.value instanceof Date) {
this.picker.date = new Date(this.value.getTime()); this.picker.date = new Date(this.value.getTime());
...@@ -492,18 +488,7 @@ export default { ...@@ -492,18 +488,7 @@ export default {
} }
this.picker.ajustScrollTop && this.picker.ajustScrollTop(); this.picker.ajustScrollTop && this.picker.ajustScrollTop();
}); });
},
resetTransformOrigin(popper) {
let placementMap = { top: 'bottom', bottom: 'top' };
let placement = popper._popper.getAttribute('x-placement').split('-')[0];
let origin = placementMap[placement];
popper._popper.style.transformOrigin = `center ${ origin }`;
} }
},
beforeDestroy() {
this.popper && this.popper.destroy();
} }
}; };
</script> </script>
export default { export default {
datepicker: { datepicker: {
today: '此刻', now: '此刻',
today: '今天',
cancel: '取消',
clear: '清空', clear: '清空',
confirm: '确定', confirm: '确定',
selectDate: '选择日期',
selectTime: '选择时间',
startTime: '开始时间',
endTime: '结束时间',
year: '',
month: '',
week: '周次', week: '周次',
weeks: { weeks: {
sun: '', sun: '',
......
...@@ -176,7 +176,11 @@ export const limitRange = function(date, ranges) { ...@@ -176,7 +176,11 @@ export const limitRange = function(date, ranges) {
import i18n from './i18n'; import i18n from './i18n';
export const $t = function(path) { export const $t = function(path, options) {
const vuei18n = Object.getPrototypeOf(this).$t;
if (typeof vuei18n === 'function') {
return vuei18n.apply(this, [path, options]);
}
const array = path.split('.'); const array = path.split('.');
let current = i18n; let current = i18n;
for (var i = 0, j = array.length; i < j; i++) { for (var i = 0, j = array.length; i < j; i++) {
......
<template> <template>
<ul class="el-dropdown__menu"> <transition name="md-fade-bottom" @after-leave="doDestroy">
<ul class="el-dropdown__menu" v-show="showPopper">
<slot></slot> <slot></slot>
</ul> </ul>
</transition>
</template> </template>
<script> <script>
import Popper from 'main/utils/popper'; import Popper from 'main/utils/vue-popper';
export default { export default {
name: 'ElDropdownMenu', name: 'ElDropdownMenu',
props: { componentName: 'ElDropdownMenu',
visible: Boolean
},
data() {
return {
popper: null
};
},
computed: {
menuAlign() {
return this.$parent.menuAlign;
}
},
mounted() {
document.body.appendChild(this.$el);
this.$nextTick(() => { mixins: [Popper],
this.popper = new Popper(this.$parent.$el, this.$el, { gpuAcceleration: false, placement: `bottom-${this.menuAlign}` });
created() {
this.$on('visible', val => {
this.showPopper = val;
}); });
}, },
destroyed() { mounted() {
setTimeout(() => { this.$parent.popperElm = this.popperElm = this.$el;
this.popper.destroy(); this.referenceElm = this.$parent.$el;
}, 300); },
computed: {
placement() {
return `bottom-${this.$parent.menuAlign}`;
}
} }
}; };
</script> </script>
<script> <script>
import Clickoutside from 'main/utils/clickoutside'; import Clickoutside from 'main/utils/clickoutside';
import emitter from 'main/mixins/emitter';
export default { export default {
name: 'ElDropdown', name: 'ElDropdown',
mixins: [emitter],
directives: { Clickoutside }, directives: { Clickoutside },
props: { props: {
...@@ -15,9 +18,8 @@ ...@@ -15,9 +18,8 @@
type: String, type: String,
default: 'end' default: 'end'
}, },
type: { type: String,
type: String size: String,
},
splitButton: Boolean splitButton: Boolean
}, },
...@@ -32,6 +34,12 @@ ...@@ -32,6 +34,12 @@
this.initEvent(); this.initEvent();
}, },
watch: {
visible(val) {
this.broadcast('ElDropdownMenu', 'visible', val);
}
},
methods: { methods: {
show() { show() {
clearTimeout(this.timeout); clearTimeout(this.timeout);
...@@ -51,7 +59,7 @@ ...@@ -51,7 +59,7 @@
initEvent() { initEvent() {
let { trigger, show, hide, handleClick, splitButton } = this; let { trigger, show, hide, handleClick, splitButton } = this;
let triggerElm = splitButton let triggerElm = splitButton
? this.$refs.trigger ? this.$refs.trigger.$el
: this.$slots.default[0].elm; : this.$slots.default[0].elm;
if (trigger === 'hover') { if (trigger === 'hover') {
...@@ -74,8 +82,7 @@ ...@@ -74,8 +82,7 @@
}, },
render(h) { render(h) {
let { hide, splitButton, visible, type } = this; let { hide, splitButton, type, size } = this;
let dropdownElm = visible ? this.$slots.dropdown : null;
var handleClick = _ => { var handleClick = _ => {
this.$emit('click'); this.$emit('click');
...@@ -84,10 +91,10 @@ ...@@ -84,10 +91,10 @@
let triggerElm = !splitButton let triggerElm = !splitButton
? this.$slots.default ? this.$slots.default
: (<el-button-group> : (<el-button-group>
<el-button type={type} nativeOn-click={handleClick}> <el-button type={type} size={size} nativeOn-click={handleClick}>
{this.$slots.default} {this.$slots.default}
</el-button> </el-button>
<el-button ref="trigger" type={type} class="el-dropdown__icon-button"> <el-button ref="trigger" type={type} size={size} class="el-dropdown__icon-button">
<i class="el-dropdown__icon el-icon-caret-bottom"></i> <i class="el-dropdown__icon el-icon-caret-bottom"></i>
</el-button> </el-button>
</el-button-group>); </el-button-group>);
...@@ -95,9 +102,7 @@ ...@@ -95,9 +102,7 @@
return ( return (
<div class="el-dropdown" v-clickoutside={hide}> <div class="el-dropdown" v-clickoutside={hide}>
{triggerElm} {triggerElm}
<transition name="md-fade-bottom"> {this.$slots.dropdown}
{dropdownElm}
</transition>
</div> </div>
); );
} }
......
...@@ -127,9 +127,12 @@ ...@@ -127,9 +127,12 @@
} }
}, },
getRules() { getRules() {
if (!this.prop) { return []; } var formRules = this.form.rules;
var rules = this.rules || (this.form.rules ? this.form.rules[this.prop] : []); var selfRuels = this.rules;
return Array.isArray(rules) ? rules : [rules];
formRules = formRules ? formRules[this.prop] : [];
return [].concat(selfRuels || formRules || []);
}, },
getFilteredRule(trigger) { getFilteredRule(trigger) {
var rules = this.getRules(); var rules = this.getRules();
...@@ -151,21 +154,22 @@ ...@@ -151,21 +154,22 @@
} }
}, },
mounted() { mounted() {
var rules = this.getRules();
rules.every(rule => {
if (rule.required) {
this.isRequired = true;
return false;
}
});
if (this.prop) { if (this.prop) {
this.dispatch('form', 'el.form.addField', [this]); this.dispatch('form', 'el.form.addField', [this]);
}
this.$on('el.form.blur', this.onFieldBlur); let rules = this.getRules();
this.$on('el.form.change', this.onFieldChange);
if (rules.length) {
rules.every(rule => {
if (rule.required) {
this.isRequired = true;
return false;
}
});
this.$on('el.form.blur', this.onFieldBlur);
this.$on('el.form.change', this.onFieldChange);
}
}
}, },
beforeDestroy() { beforeDestroy() {
this.dispatch('form', 'el.form.removeField', [this]); this.dispatch('form', 'el.form.removeField', [this]);
......
module.exports = require('./src/icon'); module.exports = require('./src/icon.vue');
export default {
name: 'ElIcon',
functional: true,
props: {
name: String
},
render(h, { props, data }) {
return (
<i
class={ 'el-icon' + props.name }
{ ...data }
{ ...{ on: data.nativeOn } }>
</i>
);
}
};
<template>
<i :class="'el-icon-' + name"></i>
</template>
<script>
export default {
name: 'ElIcon',
props: {
name: String
}
};
</script>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<input <input
class="el-input__inner" class="el-input__inner"
v-model="currentValue" v-model="currentValue"
:type="type" type="text"
:name="name" :name="name"
:placeholder="placeholder" :placeholder="placeholder"
:disabled="disabled" :disabled="disabled"
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
:minlength="minlength" :minlength="minlength"
:autocomplete="autoComplete" :autocomplete="autoComplete"
ref="input" ref="input"
@focus="$emit('onfocus', currentValue)" @focus="$emit('focus', currentValue)"
@blur="handleBlur" @blur="handleBlur"
> >
<!-- input 图标 --> <!-- input 图标 -->
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
:rows="rows" :rows="rows"
:maxlength="maxlength" :maxlength="maxlength"
:minlength="minlength" :minlength="minlength"
@focus="$emit('onfocus', currentValue)" @focus="$emit('focus', currentValue)"
@blur="handleBlur"> @blur="handleBlur">
</textarea> </textarea>
</div> </div>
...@@ -162,6 +162,7 @@ ...@@ -162,6 +162,7 @@
'currentValue'(val) { 'currentValue'(val) {
this.$emit('input', val); this.$emit('input', val);
this.$emit('change', val);
this.dispatch('form-item', 'el.form.change', [val]); this.dispatch('form-item', 'el.form.change', [val]);
} }
} }
......
...@@ -11,5 +11,7 @@ ...@@ -11,5 +11,7 @@
"repository": "https://github.com/element-component/element/tree/master/packages/loading", "repository": "https://github.com/element-component/element/tree/master/packages/loading",
"author": "elemefe", "author": "elemefe",
"license": "MIT", "license": "MIT",
"dependencies": {} "dependencies": {
"wind-dom": "0.0.3"
}
} }
import { addClass } from 'wind-dom/src/class';
class Spinner { class Spinner {
constructor() { constructor() {
let spinner = document.createElement('div'); let spinner = document.createElement('div');
spinner.classList.add('el-loading-spinner'); addClass(spinner, 'el-loading-spinner');
[1, 2, 3].forEach(index => { [1, 2, 3].forEach(index => {
let bubble = document.createElement('div'); let bubble = document.createElement('div');
bubble.classList.add('el-loading-bubble', `bubble${ index }`); addClass(bubble, `el-loading-bubble bubble${ index }`);
spinner.appendChild(bubble); spinner.appendChild(bubble);
}); });
this.el = spinner; this.el = spinner;
......
...@@ -27,12 +27,7 @@ ...@@ -27,12 +27,7 @@
type: String, type: String,
default: '' default: ''
}, },
defaultOpeneds: { defaultOpeneds: Array,
type: Array,
default() {
return [];
}
},
theme: { theme: {
type: String, type: String,
default: 'light' default: 'light'
...@@ -43,7 +38,7 @@ ...@@ -43,7 +38,7 @@
data() { data() {
return { return {
activeIndex: this.defaultActive, activeIndex: this.defaultActive,
openedMenus: this.defaultOpeneds.slice(0), openedMenus: this.defaultOpeneds ? this.defaultOpeneds.slice(0) : [],
menuItems: {}, menuItems: {},
submenus: {} submenus: {}
}; };
...@@ -63,6 +58,7 @@ ...@@ -63,6 +58,7 @@
openMenu(index, indexPath) { openMenu(index, indexPath) {
let openedMenus = this.openedMenus; let openedMenus = this.openedMenus;
if (openedMenus.indexOf(index) !== -1) return; if (openedMenus.indexOf(index) !== -1) return;
// 将不在该菜单路径下的其余菜单收起
if (this.uniqueOpened) { if (this.uniqueOpened) {
this.openedMenus = openedMenus.filter(index => { this.openedMenus = openedMenus.filter(index => {
return indexPath.indexOf(index) !== -1; return indexPath.indexOf(index) !== -1;
...@@ -92,29 +88,28 @@ ...@@ -92,29 +88,28 @@
this.broadcast('submenu', 'item-select', [index, indexPath]); this.broadcast('submenu', 'item-select', [index, indexPath]);
this.openedMenus = []; this.openedMenus = [];
} else { } else {
this.openActiveItemMenus();
}
if (this.router && route) {
this.$router.push(route);
}
},
openActiveItemMenus() {
let index = this.activeIndex;
if (index && this.mode === 'vertical') {
let indexPath = this.menuItems[index].indexPath;
// 展开该菜单项的路径上所有子菜单 // 展开该菜单项的路径上所有子菜单
indexPath.forEach(index => { indexPath.forEach(index => {
let submenu = this.submenus[index]; let submenu = this.submenus[index];
submenu && this.openMenu(index, submenu.indexPath); submenu && this.openMenu(index, submenu.indexPath);
}); });
} }
if (this.router && route) {
this.$router.push(route);
}
} }
}, },
mounted() { mounted() {
let index = this.activeIndex; this.openActiveItemMenus();
if (index && this.mode === 'vertical') {
let indexPath = this.menuItems[index].indexPath;
// 展开该菜单项的路径上所有子菜单
indexPath.forEach(index => {
let submenu = this.submenus[index];
submenu && this.openMenu(index, submenu.indexPath);
});
}
} }
}; };
</script> </script>
...@@ -12,5 +12,6 @@ ...@@ -12,5 +12,6 @@
"author": "elemefe", "author": "elemefe",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"wind-dom": "0.0.3"
} }
} }
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
import Popup from 'vue-popup'; import Popup from 'vue-popup';
import ElInput from 'packages/input/index.js'; import ElInput from 'packages/input/index.js';
import { addClass, removeClass } from 'wind-dom/src/class';
export default { export default {
mixins: [ Popup ], mixins: [ Popup ],
...@@ -113,7 +114,7 @@ ...@@ -113,7 +114,7 @@
var inputPattern = this.inputPattern; var inputPattern = this.inputPattern;
if (inputPattern && !inputPattern.test(this.inputValue || '')) { if (inputPattern && !inputPattern.test(this.inputValue || '')) {
this.editorErrorMessage = this.inputErrorMessage || '输入的数据不合法!'; this.editorErrorMessage = this.inputErrorMessage || '输入的数据不合法!';
this.$refs.input.$el.querySelector('input').classList.add('invalid'); addClass(this.$refs.input.$el.querySelector('input'), 'invalid');
return false; return false;
} }
var inputValidator = this.inputValidator; var inputValidator = this.inputValidator;
...@@ -121,7 +122,7 @@ ...@@ -121,7 +122,7 @@
var validateResult = inputValidator(this.inputValue); var validateResult = inputValidator(this.inputValue);
if (validateResult === false) { if (validateResult === false) {
this.editorErrorMessage = this.inputErrorMessage || '输入的数据不合法!'; this.editorErrorMessage = this.inputErrorMessage || '输入的数据不合法!';
this.$refs.input.$el.querySelector('input').classList.add('invalid'); addClass(this.$refs.input.$el.querySelector('input'), 'invalid');
return false; return false;
} }
if (typeof validateResult === 'string') { if (typeof validateResult === 'string') {
...@@ -131,7 +132,7 @@ ...@@ -131,7 +132,7 @@
} }
} }
this.editorErrorMessage = ''; this.editorErrorMessage = '';
this.$refs.input.$el.querySelector('input').classList.remove('invalid'); removeClass(this.$refs.input.$el.querySelector('input'), 'invalid');
return true; return true;
} }
}, },
......
...@@ -168,14 +168,9 @@ export default { ...@@ -168,14 +168,9 @@ export default {
this.oldValue = event.target.value; this.oldValue = event.target.value;
}, },
handleChange(event) { handleChange({ target }) {
const target = event.target;
this.$parent.internalCurrentPage = this.$parent.getValidCurrentPage(target.value); this.$parent.internalCurrentPage = this.$parent.getValidCurrentPage(target.value);
this.$parent.$emit('currentchange', this.$parent.internalCurrentPage);
if (target.value !== this.oldValue && Number(target.value) === this.$parent.internalCurrentPage) {
this.$parent.$emit('currentchange', this.$parent.internalCurrentPage);
}
this.oldValue = null; this.oldValue = null;
} }
}, },
...@@ -189,12 +184,11 @@ export default { ...@@ -189,12 +184,11 @@ export default {
type="number" type="number"
min={ 1 } min={ 1 }
max={ this.pageCount } max={ this.pageCount }
value={ this.$parent.internalCurrentPage } domProps-value={ this.$parent.internalCurrentPage }
on-change={ this.handleChange } on-change={ this.handleChange }
on-focus={ this.handleFocus } on-focus={ this.handleFocus }
style={{ width: '30px' }} style={{ width: '30px' }}
number number/>
lazy/>
</span> </span>
); );
......
...@@ -46,65 +46,59 @@ export default { ...@@ -46,65 +46,59 @@ export default {
transition: { transition: {
type: String, type: String,
default: 'fade-in-linear' default: 'fade-in-linear'
},
options: {
default() {
return {
gpuAcceleration: false
};
}
} }
}, },
mounted() { mounted() {
setTimeout(() => { let _timer;
let _timer; const reference = this.reference || this.$refs.reference || this.$slots.reference[0].elm;
const reference = this.reference || this.$refs.reference || this.$slots.reference[0].elm; const popper = this.popper || this.$refs.popper;
this.$nextTick(() => { this.$nextTick(() => {
if (this.trigger === 'click') { if (this.trigger === 'click') {
on(reference, 'click', () => { this.showPopper = !this.showPopper; }); on(reference, 'click', () => { this.showPopper = !this.showPopper; });
on(document, 'click', (e) => { on(document, 'click', (e) => {
if (!this.$el || if (!this.$el ||
!reference || !reference ||
this.$el.contains(e.target) || this.$el.contains(e.target) ||
reference.contains(e.target)) return; reference.contains(e.target) ||
!popper ||
popper.contains(e.target)) return;
this.showPopper = false;
});
} else if (this.trigger === 'hover') {
on(reference, 'mouseenter', () => {
this.showPopper = true;
clearTimeout(_timer);
});
on(reference, 'mouseleave', () => {
_timer = setTimeout(() => {
this.showPopper = false; this.showPopper = false;
}); }, 200);
} else if (this.trigger === 'hover') { });
on(reference, 'mouseenter', () => { } else {
this.showPopper = true; if ([].slice.call(reference.children).length) {
clearTimeout(_timer); const children = reference.childNodes;
});
on(reference, 'mouseleave', () => {
_timer = setTimeout(() => {
this.showPopper = false;
}, 200);
});
} else {
if ([].slice.call(reference.children).length) {
const children = reference.childNodes;
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
if (children[i].nodeName === 'INPUT') { if (children[i].nodeName === 'INPUT') {
on(children[i], 'focus', () => { this.showPopper = true; }); on(children[i], 'focus', () => { this.showPopper = true; });
on(children[i], 'blur', () => { this.showPopper = false; }); on(children[i], 'blur', () => { this.showPopper = false; });
break; break;
}
} }
} else if (
reference.nodeName === 'INPUT' ||
reference.nodeName === 'TEXTAREA'
) {
on(reference, 'focus', () => { this.showPopper = true; });
on(reference, 'blur', () => { this.showPopper = false; });
} else {
on(reference, 'mousedown', () => { this.showPopper = true; });
on(reference, 'mouseup', () => { this.showPopper = false; });
} }
} else if (
reference.nodeName === 'INPUT' ||
reference.nodeName === 'TEXTAREA'
) {
on(reference, 'focus', () => { this.showPopper = true; });
on(reference, 'blur', () => { this.showPopper = false; });
} else {
on(reference, 'mousedown', () => { this.showPopper = true; });
on(reference, 'mouseup', () => { this.showPopper = false; });
} }
}); }
}, 100); });
}, },
destroyed() { destroyed() {
......
...@@ -11,5 +11,7 @@ ...@@ -11,5 +11,7 @@
"repository": "https://github.com/element-component/element/tree/master/packages/rate", "repository": "https://github.com/element-component/element/tree/master/packages/rate",
"author": "elemefe", "author": "elemefe",
"license": "MIT", "license": "MIT",
"dependencies": {} "dependencies": {
"wind-dom": "0.0.3"
}
} }
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
</template> </template>
<script type="text/babel"> <script type="text/babel">
import { hasClass } from 'wind-dom/src/class';
export default { export default {
name: 'el-rate', name: 'el-rate',
...@@ -223,10 +225,10 @@ ...@@ -223,10 +225,10 @@
} }
if (this.allowHalf) { if (this.allowHalf) {
let target = event.target; let target = event.target;
if (target.classList.contains('el-rate__item')) { if (hasClass(target, 'el-rate__item')) {
target = target.querySelector('.el-rate__icon'); target = target.querySelector('.el-rate__icon');
} }
if (target.classList.contains('el-rate__decimal')) { if (hasClass(target, 'el-rate__decimal')) {
target = target.parentNode; target = target.parentNode;
} }
this.pointerAtLeftHalf = event.offsetX * 2 <= target.clientWidth; this.pointerAtLeftHalf = event.offsetX * 2 <= target.clientWidth;
......
<template> <template>
<div class="el-select-dropdown"> <div
class="el-select-dropdown"
:class="{ 'is-multiple': $parent.multiple }"
:style="{ minWidth: minWidth }">
<slot></slot> <slot></slot>
</div> </div>
</template> </template>
<script type="text/babel"> <script type="text/babel">
import Popper from 'main/utils/popper'; import Popper from 'main/utils/vue-popper';
export default { export default {
name: 'el-select-dropdown', name: 'el-select-dropdown',
componentName: 'select-dropdown', componentName: 'select-dropdown',
data() { mixins: [Popper],
return {
popper: null
};
},
created() {
this.$on('updatePopper', this.updatePopper);
this.$on('destroyPopper', this.destroyPopper);
},
methods: { props: {
updatePopper() { placement: {
if (this.popper) { default: 'bottom-start'
this.$nextTick(() => {
this.popper.update();
});
} else {
this.$nextTick(() => {
this.popper = new Popper(this.$parent.$refs.reference.$el, this.$el, {
gpuAcceleration: false,
placement: 'bottom-start',
boundariesPadding: 0,
forceAbsolute: true
});
this.popper.onCreate(popper => {
this.resetTransformOrigin(popper);
});
});
}
}, },
destroyPopper() { boundariesPadding: {
if (this.popper) { default: 0
this.resetTransformOrigin(this.popper);
setTimeout(() => {
this.popper.destroy();
this.popper = null;
}, 300);
}
}, },
resetTransformOrigin(popper) { options: {
let placementMap = { top: 'bottom', bottom: 'top' }; default() {
let placement = popper._popper.getAttribute('x-placement').split('-')[0]; return {
let origin = placementMap[placement]; forceAbsolute: true,
popper._popper.style.transformOrigin = `center ${ origin }`; gpuAcceleration: false
};
}
} }
}, },
beforeDestroy() { data() {
if (this.popper) { return {
this.popper.destroy(); minWidth: ''
};
},
watch: {
'$parent.inputWidth'() {
this.minWidth = this.$parent.$el.getBoundingClientRect().width + 'px';
} }
},
mounted() {
this.referenceElm = this.$parent.$refs.reference.$el;
this.$parent.popperElm = this.popperElm = this.$el;
this.$on('updatePopper', this.updatePopper);
this.$on('destroyPopper', this.destroyPopper);
} }
}; };
</script> </script>
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
"repository": "https://github.com/element-component/element/tree/master/packages/select", "repository": "https://github.com/element-component/element/tree/master/packages/select",
"devDependencies": { "devDependencies": {
"throttle-debounce": "^1.0.1", "throttle-debounce": "^1.0.1",
"vue-clickoutside": "0.0.4" "vue-clickoutside": "0.0.4",
"wind-dom": "0.0.3"
} }
} }
<template> <template>
<div class="el-select" :class="{ 'is-multiple': multiple, 'is-small': size === 'small' }"> <div
class="el-select"
v-clickoutside="handleClose"
:class="{ 'is-multiple': multiple, 'is-small': size === 'small' }">
<div class="el-select__tags" v-if="multiple" @click.stop="toggleMenu" ref="tags" :style="{ 'max-width': inputWidth - 32 + 'px' }"> <div class="el-select__tags" v-if="multiple" @click.stop="toggleMenu" ref="tags" :style="{ 'max-width': inputWidth - 32 + 'px' }">
<transition-group @after-leave="resetInputHeight"> <transition-group @after-leave="resetInputHeight">
<el-tag <el-tag
...@@ -25,7 +28,7 @@ ...@@ -25,7 +28,7 @@
v-model="query" v-model="query"
:debounce="remote ? 300 : 0" :debounce="remote ? 300 : 0"
v-if="filterable" v-if="filterable"
:style="{ width: inputLength + 'px' }" :style="{ width: inputLength + 'px', 'max-width': inputWidth - 42 + 'px' }"
ref="input"> ref="input">
</div> </div>
<el-input <el-input
...@@ -45,10 +48,9 @@ ...@@ -45,10 +48,9 @@
@keydown.native.tab="visible = false" @keydown.native.tab="visible = false"
@mouseenter.native="inputHovering = true" @mouseenter.native="inputHovering = true"
@mouseleave.native="inputHovering = false" @mouseleave.native="inputHovering = false"
:icon="iconClass" :icon="iconClass">
v-element-clickoutside="handleClose">
</el-input> </el-input>
<transition name="md-fade-bottom"> <transition name="md-fade-bottom" @after-leave="doDestroy">
<el-select-menu <el-select-menu
ref="popper" ref="popper"
v-show="visible && nodataText !== false"> v-show="visible && nodataText !== false">
...@@ -68,6 +70,7 @@ ...@@ -68,6 +70,7 @@
import ElTag from 'packages/tag/index.js'; import ElTag from 'packages/tag/index.js';
import debounce from 'throttle-debounce/debounce'; import debounce from 'throttle-debounce/debounce';
import Clickoutside from 'main/utils/clickoutside'; import Clickoutside from 'main/utils/clickoutside';
import { addClass, removeClass } from 'wind-dom/src/class';
export default { export default {
mixins: [emitter], mixins: [emitter],
...@@ -93,10 +96,10 @@ ...@@ -93,10 +96,10 @@
if (icon) { if (icon) {
if (criteria) { if (criteria) {
icon.addEventListener('click', this.deleteSelected); icon.addEventListener('click', this.deleteSelected);
icon.classList.add('is-show-close'); addClass(icon, 'is-show-close');
} else { } else {
icon.removeEventListener('click', this.deleteSelected); icon.removeEventListener('click', this.deleteSelected);
icon.classList.remove('is-show-close'); removeClass(icon, 'is-show-close');
} }
} }
return criteria; return criteria;
...@@ -127,9 +130,7 @@ ...@@ -127,9 +130,7 @@
ElTag ElTag
}, },
directives: { directives: { Clickoutside },
ElementClickoutside: Clickoutside
},
props: { props: {
name: String, name: String,
...@@ -270,7 +271,7 @@ ...@@ -270,7 +271,7 @@
if (!val) { if (!val) {
this.$refs.reference.$el.querySelector('input').blur(); this.$refs.reference.$el.querySelector('input').blur();
if (this.$el.querySelector('.el-input__icon')) { if (this.$el.querySelector('.el-input__icon')) {
this.$el.querySelector('.el-input__icon').classList.remove('is-reverse'); removeClass(this.$el.querySelector('.el-input__icon'), 'is-reverse');
} }
this.broadcast('select-dropdown', 'destroyPopper'); this.broadcast('select-dropdown', 'destroyPopper');
if (this.$refs.input) { if (this.$refs.input) {
...@@ -287,7 +288,7 @@ ...@@ -287,7 +288,7 @@
} }
} else { } else {
if (this.$el.querySelector('.el-input__icon')) { if (this.$el.querySelector('.el-input__icon')) {
this.$el.querySelector('.el-input__icon').classList.add('is-reverse'); addClass(this.$el.querySelector('.el-input__icon'), 'is-reverse');
} }
this.broadcast('select-dropdown', 'updatePopper'); this.broadcast('select-dropdown', 'updatePopper');
if (this.filterable) { if (this.filterable) {
...@@ -316,6 +317,10 @@ ...@@ -316,6 +317,10 @@
}, },
methods: { methods: {
doDestroy() {
this.$refs.popper.doDestroy();
},
handleClose() { handleClose() {
this.visible = false; this.visible = false;
}, },
...@@ -362,7 +367,7 @@ ...@@ -362,7 +367,7 @@
resetInputState(e) { resetInputState(e) {
if (e.keyCode !== 8) this.toggleLastOptionHitState(false); if (e.keyCode !== 8) this.toggleLastOptionHitState(false);
this.inputLength = this.$refs.input.value.length * 12 + 20; this.inputLength = this.$refs.input.value.length * 15 + 20;
}, },
resetInputHeight() { resetInputHeight() {
...@@ -486,7 +491,7 @@ ...@@ -486,7 +491,7 @@
}, },
onInputChange() { onInputChange() {
if (this.filterable) { if (this.filterable && this.selectedLabel !== this.value) {
this.query = this.selectedLabel; this.query = this.selectedLabel;
} }
}, },
......
...@@ -26,10 +26,11 @@ ...@@ -26,10 +26,11 @@
</div> </div>
</template> </template>
<script type="text/ecmascript-6"> <script type="text/babel">
import Popper from 'main/utils/popper'; import Popper from 'main/utils/popper';
import ElInputNumber from 'packages/input-number/index.js'; import ElInputNumber from 'packages/input-number/index.js';
import { getStyle } from 'wind-dom/src/style'; import { getStyle } from 'wind-dom/src/style';
import { addClass, removeClass } from 'wind-dom/src/class';
export default { export default {
name: 'ElSlider', name: 'ElSlider',
...@@ -125,8 +126,8 @@ ...@@ -125,8 +126,8 @@
let placementMap = { top: 'bottom', bottom: 'top' }; let placementMap = { top: 'bottom', bottom: 'top' };
let placement = this.popper._popper.getAttribute('x-placement').split('-')[0]; let placement = this.popper._popper.getAttribute('x-placement').split('-')[0];
let origin = placementMap[placement]; let origin = placementMap[placement];
this.popper._popper.classList.add(placement); addClass(this.popper._popper, placement);
this.popper._popper.classList.remove(placementMap[placement]); removeClass(this.popper._popper, placementMap[placement]);
this.popper._popper.style.transformOrigin = `center ${ origin }`; this.popper._popper.style.transformOrigin = `center ${ origin }`;
}, },
......
...@@ -12,17 +12,18 @@ ...@@ -12,17 +12,18 @@
<i class="el-step__line-inner" :style="lineStyle"></i> <i class="el-step__line-inner" :style="lineStyle"></i>
</div> </div>
<slot <span class="el-step__icon">
v-if="currentStatus !== 'success' && currentStatus !== 'error'" <slot
name="icon"> v-if="currentStatus !== 'success' && currentStatus !== 'error'"
<i v-if="icon" :class="['el-step__icon', 'el-icon-' + icon]"></i> name="icon">
<div v-else>{{ index + 1 }}</div> <i v-if="icon" :class="['el-icon-' + icon]"></i>
</slot> <div v-else>{{ index + 1 }}</div>
<i </slot>
v-else <i
class="el-step__icon" v-else
:class="['el-icon-' + (currentStatus === 'success' ? 'check' : 'close')]"> :class="['el-icon-' + (currentStatus === 'success' ? 'check' : 'close')]">
</i> </i>
</span>
</div> </div>
<div <div
class="el-step__main" class="el-step__main"
...@@ -59,8 +60,8 @@ export default { ...@@ -59,8 +60,8 @@ export default {
data() { data() {
return { return {
index: -1, index: -1,
style: { width: 0, height: 0 }, style: { width: '', height: '' },
lineStyle: { width: 0, height: 0 }, lineStyle: { width: '', height: '' },
mainOffset: 0, mainOffset: 0,
currentStatus: this.status currentStatus: this.status
}; };
......
...@@ -155,11 +155,6 @@ export default { ...@@ -155,11 +155,6 @@ export default {
grid.$emit('rowclick', row, event); grid.$emit('rowclick', row, event);
}, },
handleCreate(vm) {
document.body.appendChild(vm.$refs.popper);
vm.updatePopper();
},
$getPropertyText(row, property, columnId) { $getPropertyText(row, property, columnId) {
let grid = this.$parent; let grid = this.$parent;
const column = getColumnById(grid, columnId); const column = getColumnById(grid, columnId);
......
...@@ -190,7 +190,6 @@ export default { ...@@ -190,7 +190,6 @@ export default {
return _self.showTooltipWhenOverflow return _self.showTooltipWhenOverflow
? <el-tooltip ? <el-tooltip
on-created={ this.handleCreate }
effect={ this.effect } effect={ this.effect }
placement="top" placement="top"
disabled={ this.tooltipDisabled }> disabled={ this.tooltipDisabled }>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
font-variant: normal; font-variant: normal;
text-transform: none; text-transform: none;
line-height: 1; line-height: 1;
vertical-align: bottom; vertical-align: baseline;
display: inline-block; display: inline-block;
/* Better Font Rendering =========== */ /* Better Font Rendering =========== */
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
@import "./radio.css"; @import "./radio.css";
@import "./switch.css"; @import "./switch.css";
@import "./dropdown.css"; @import "./dropdown.css";
@import "./dropdown-menu.css";
@import "./loading.css"; @import "./loading.css";
@import "./dialog.css"; @import "./dialog.css";
@import "./table.css"; @import "./table.css";
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
@component-namespace el { @component-namespace el {
@b select-dropdown { @b select-dropdown {
width: 100%;
position: absolute; position: absolute;
z-index: 1001; z-index: 1001;
border: solid 1px #d3dce6; border: solid 1px #d3dce6;
...@@ -12,5 +11,44 @@ ...@@ -12,5 +11,44 @@
background-color: #fff; background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04); box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
box-sizing: border-box; box-sizing: border-box;
margin: 5px 0;
@when multiple {
& .el-select-dropdown__item.selected {
color: #20A0FF;
background-color: #fff;
&.hover {
background-color: #E5E9F2;
}
&::after {
position: absolute;
right: 10px;
font-family: 'element-icons';
content: "\E608";
font-size: 11px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}
}
@b select-dropdown__nodata {
padding: 10px 0;
margin: 0;
text-align: center;
color: #999;
}
@b select-dropdown__list {
list-style: none;
padding: 6px 0;
margin: 0;
width: 100%;
max-height: 274px;
box-sizing: border-box;
overflow-y: auto;
} }
} }
...@@ -25,27 +25,6 @@ ...@@ -25,27 +25,6 @@
} }
} }
& .el-select-dropdown {
margin: 5px 0;
& p.el-select-dropdown__nodata {
padding: 10px 0;
margin: 0;
text-align: center;
color: #999;
}
}
& .el-select-dropdown__list {
list-style: none;
padding: 6px 0;
margin: 0;
width: 100%;
max-height: 274px;
box-sizing: border-box;
overflow-y: auto;
}
& .el-input { & .el-input {
& .el-input__icon { & .el-input__icon {
color: #c0ccda; color: #c0ccda;
...@@ -95,27 +74,6 @@ ...@@ -95,27 +74,6 @@
} }
} }
@when multiple {
& .el-select-dropdown__item.selected {
color: #20A0FF;
background-color: #fff;
&.hover {
background-color: #E5E9F2;
}
&::after {
position: absolute;
right: 10px;
font-family: 'element-icons';
content: "\E608";
font-size: 11px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}
@e input { @e input {
border: none; border: none;
outline: none; outline: none;
......
...@@ -19,10 +19,6 @@ ...@@ -19,10 +19,6 @@
& .el-step__main { & .el-step__main {
padding-left: 10px; padding-left: 10px;
} }
& .el-step__description {
width: 300px;
}
} }
@e line { @e line {
...@@ -69,6 +65,10 @@ ...@@ -69,6 +65,10 @@
@e icon { @e icon {
line-height: 28px; line-height: 28px;
> * {
line-height: inherit;
}
} }
@e head { @e head {
...@@ -149,7 +149,7 @@ ...@@ -149,7 +149,7 @@
@e title { @e title {
font-size: 14px; font-size: 14px;
margin-top: 5px; line-height: 32px;
display: inline-block; display: inline-block;
@when process { @when process {
......
...@@ -3,9 +3,8 @@ ...@@ -3,9 +3,8 @@
@import "../../date-picker/src/css/vars.css"; @import "../../date-picker/src/css/vars.css";
.time-select { .time-select {
min-width: 200px;
margin: 5px 0; margin: 5px 0;
width: 100%; min-width: 0;
} }
.time-select .el-picker-panel__content { .time-select .el-picker-panel__content {
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
<span <span
v-if="node.loading" v-if="node.loading"
class="el-tree-node__icon el-icon-loading" class="el-tree-node__icon el-icon-loading"
> >
</span> </span>
<span class="el-tree-node__label">{{ node.label }}</span> <span class="el-tree-node__label" v-html="node.label"></span>
</div> </div>
<collapse-transition> <collapse-transition>
<div class="el-tree-node__children" <div class="el-tree-node__children"
...@@ -94,9 +94,9 @@ ...@@ -94,9 +94,9 @@
} }
}, },
handleCheckChange(checked) { handleCheckChange(ev) {
if (!this.node.indeterminate) { if (!this.node.indeterminate) {
this.node.setChecked(checked, true); this.node.setChecked(ev.target.checked, true);
} }
} }
}, },
......
...@@ -31,18 +31,13 @@ export default { ...@@ -31,18 +31,13 @@ export default {
}; };
} }
}, },
multiple: { data: Object,
type: Boolean, multiple: Boolean,
default: false
},
name: { name: {
type: String, type: String,
default: 'file' default: 'file'
}, },
withCredentials: { withCredentials: Boolean,
type: Boolean,
default: false
},
thumbnailMode: Boolean, thumbnailMode: Boolean,
showUploadList: { showUploadList: {
type: Boolean, type: Boolean,
...@@ -179,6 +174,7 @@ export default { ...@@ -179,6 +174,7 @@ export default {
'with-credentials': this.withCredentials, 'with-credentials': this.withCredentials,
headers: this.headers, headers: this.headers,
name: this.name, name: this.name,
data: this.data,
accept: this.thumbnailMode ? 'image/*' : this.accept, accept: this.thumbnailMode ? 'image/*' : this.accept,
'on-start': this.handleStart, 'on-start': this.handleStart,
'on-progress': this.handleProgress, 'on-progress': this.handleProgress,
......
...@@ -34,6 +34,7 @@ export default { ...@@ -34,6 +34,7 @@ export default {
type: String, type: String,
default: 'file' default: 'file'
}, },
data: Object,
headers: Object, headers: Object,
withCredentials: Boolean, withCredentials: Boolean,
multiple: Boolean, multiple: Boolean,
...@@ -133,6 +134,7 @@ export default { ...@@ -133,6 +134,7 @@ export default {
headers: this.headers, headers: this.headers,
withCredentials: this.withCredentials, withCredentials: this.withCredentials,
file: file, file: file,
data: this.data,
filename: this.name, filename: this.name,
onProgress: e => { onProgress: e => {
this.onProgress(e, file); this.onProgress(e, file);
......
...@@ -127,7 +127,7 @@ if (typeof window !== 'undefined' && window.Vue) { ...@@ -127,7 +127,7 @@ if (typeof window !== 'undefined' && window.Vue) {
}; };
module.exports = { module.exports = {
version: '1.0.0-rc.5', version: '1.0.0-rc.6',
install, install,
SelectDropdown, SelectDropdown,
Pagination, Pagination,
......
...@@ -12,7 +12,7 @@ function broadcast(componentName, eventName, params) { ...@@ -12,7 +12,7 @@ function broadcast(componentName, eventName, params) {
export default { export default {
methods: { methods: {
dispatch(componentName, eventName, params) { dispatch(componentName, eventName, params) {
var parent = this.$parent; var parent = this.$parent || this.$root;
var name = parent.$options.componentName; var name = parent.$options.componentName;
while (parent && (!name || name !== componentName)) { while (parent && (!name || name !== componentName)) {
......
import { on, off } from 'wind-dom/src/event';
/** /**
* v-clickoutside * v-clickoutside
* @desc 点击元素外面才会触发的事件 * @desc 点击元素外面才会触发的事件
...@@ -11,7 +13,10 @@ const clickoutsideContext = '@@clickoutsideContext'; ...@@ -11,7 +13,10 @@ const clickoutsideContext = '@@clickoutsideContext';
export default { export default {
bind(el, binding, vnode) { bind(el, binding, vnode) {
const documentHandler = function(e) { const documentHandler = function(e) {
if (!vnode.context || el.contains(e.target)) return; if (!vnode.context ||
el.contains(e.target) ||
!vnode.context.popperElm ||
vnode.context.popperElm.contains(e.target)) return;
if (binding.expression) { if (binding.expression) {
vnode.context[el[clickoutsideContext].methodName](); vnode.context[el[clickoutsideContext].methodName]();
} else { } else {
...@@ -23,7 +28,7 @@ export default { ...@@ -23,7 +28,7 @@ export default {
methodName: binding.expression, methodName: binding.expression,
bindingFn: binding.value bindingFn: binding.value
}; };
document.addEventListener('click', documentHandler); on(document, 'click', documentHandler);
}, },
update(el, binding) { update(el, binding) {
...@@ -32,7 +37,7 @@ export default { ...@@ -32,7 +37,7 @@ export default {
}, },
unbind(el) { unbind(el) {
document.removeEventListener('click', el[clickoutsideContext].documentHandler); off(document, 'click', el[clickoutsideContext].documentHandler);
}, },
install(Vue) { install(Vue) {
......
import PopperJS from './popper'; import PopperJS from './popper';
import { PopupManager } from 'vue-popup';
/** /**
* @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper. * @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper.
...@@ -26,10 +27,16 @@ export default { ...@@ -26,10 +27,16 @@ export default {
value: Boolean, value: Boolean,
visibleArrow: Boolean, visibleArrow: Boolean,
transition: String, transition: String,
appendToBody: {
type: Boolean,
default: true
},
options: { options: {
type: Object, type: Object,
default() { default() {
return {}; return {
gpuAcceleration: false
};
} }
} }
}, },
...@@ -62,59 +69,48 @@ export default { ...@@ -62,59 +69,48 @@ export default {
} }
const options = this.options; const options = this.options;
const popper = this.popper || this.$refs.popper; const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper;
const reference = this.reference || this.$refs.reference || this.$slots.reference[0].elm; const reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference || this.$slots.reference[0].elm;
if (!popper || !reference) return; if (!popper || !reference) return;
if (this.visibleArrow) {
this.appendArrow(popper);
}
if (this.visibleArrow) this.appendArrow(popper);
if (this.appendToBody) document.body.appendChild(this.popperElm);
if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) { if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
this.popperJS.destroy(); this.popperJS.destroy();
} }
options.placement = this.placement; options.placement = this.placement;
options.offset = this.offset; options.offset = this.offset;
this.popperJS = new PopperJS(reference, popper, options);
this.$nextTick(() => { this.popperJS.onCreate(_ => {
this.popperJS = new PopperJS( this.$emit('created', this);
reference, this.resetTransformOrigin();
popper,
options
);
this.popperJS.onCreate(popper => {
this.resetTransformOrigin(popper);
this.$emit('created', this);
});
}); });
this.popperJS._popper.style.zIndex = PopupManager.nextZIndex();
}, },
updatePopper() { updatePopper() {
if (this.popperJS) { this.popperJS ? this.popperJS.update() : this.createPopper();
this.popperJS.update();
} else {
this.createPopper();
}
}, },
doDestroy() { doDestroy() {
if (this.showPopper) return; if (this.showPopper || !this.popperJS) return;
this.popperJS.destroy(); this.popperJS.destroy();
this.popperJS = null; this.popperJS = null;
}, },
destroyPopper() { destroyPopper() {
if (this.popperJS) { if (this.popperJS) {
this.resetTransformOrigin(this.popperJS); this.resetTransformOrigin();
} }
}, },
resetTransformOrigin(popper) { resetTransformOrigin() {
let placementMap = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' }; let placementMap = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
let placement = popper._popper.getAttribute('x-placement').split('-')[0]; let placement = this.popperJS._popper.getAttribute('x-placement').split('-')[0];
let origin = placementMap[placement]; let origin = placementMap[placement];
popper._popper.style.transformOrigin = ['top', 'bottom'].indexOf(placement) > -1 ? `center ${ origin }` : `${ origin } center`; this.popperJS._popper.style.transformOrigin = ['top', 'bottom'].indexOf(placement) > -1 ? `center ${ origin }` : `${ origin } center`;
}, },
appendArrow(element) { appendArrow(element) {
...@@ -144,8 +140,9 @@ export default { ...@@ -144,8 +140,9 @@ export default {
}, },
beforeDestroy() { beforeDestroy() {
if (this.popperJS) { this.doDestroy();
this.popperJS.destroy(); this.popperElm &&
} document.body.contains(this.popperElm) &&
document.body.removeChild(this.popperElm);
} }
}; };
{
"env": {
"mocha": true
},
"globals": {
"expect": true,
"sinon": true
}
}
// Polyfill fn.bind() for PhantomJS
/* eslint-disable no-extend-native */
Function.prototype.bind = require('function-bind');
require('packages/theme-default/src/index.css');
// require all test files (files that ends with .spec.js)
const testsContext = require.context('./specs', true, /\.spec$/);
testsContext.keys().forEach(testsContext);
// require all src files except main.js for coverage.
// you can also change this to match only the subset of files that
// you want coverage for.
const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/);
srcContext.keys().forEach(srcContext);
var webpackConfig = require('../../build/cooking.test');
// no need for app entry during tests
delete webpackConfig.entry;
module.exports = function(config) {
config.set({
// to run in additional browsers:
// 1. install corresponding karma launcher
// http://karma-runner.github.io/0.13/config/browsers.html
// 2. add it to the `browsers` array below.
browsers: ['PhantomJS'],
frameworks: ['mocha', 'sinon-chai'],
reporters: ['spec', 'coverage'],
files: ['./index.js'],
preprocessors: {
'./index.js': ['webpack', 'sourcemap']
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
coverageReporter: {
dir: './coverage',
reporters: [
{ type: 'lcov', subdir: '.' },
{ type: 'text-summary' }
]
}
});
};
import { createTest, createVue } from '../util';
import TimeSelect from 'packages/time-select';
import Vue from 'vue';
describe('TimeSelect', () => {
it('should render correct contents', done => {
const vm = createTest(TimeSelect, {
pickerOptions: {
start: '08:30',
step: '00:15',
end: '18:30'
},
placeholder: 'test'
}, true);
vm.$el.querySelector('input').blur();
vm.$el.querySelector('input').focus();
vm.$el.querySelector('input').blur();
Vue.nextTick(_ => {
expect(vm.picker.start).to.equal('08:30');
expect(vm.picker.end).to.equal('18:30');
expect(vm.picker.step).to.equal('00:15');
expect(vm.$el.querySelector('input').getAttribute('placeholder')).to.equal('test');
done();
});
});
it('click time', done => {
const vm = createVue({
template: `
<div>
<el-time-select ref="compo" v-model="value">
</el-time-select>
</div>
`,
data() {
return {
value: ''
};
}
}, true);
vm.$el.querySelector('input').blur();
vm.$el.querySelector('input').focus();
vm.$el.querySelector('input').blur();
Vue.nextTick(_ => {
const items = vm.$refs.compo.picker.$el.querySelectorAll('.time-select-item');
const target = items[4];
const time = target.textContent.trim();
target.click();
Vue.nextTick(_ => {
expect(vm.value).to.equal(time);
done();
});
});
});
});
import Vue from 'vue/dist/vue';
import Element from 'main/index.js';
Vue.use(Element);
let id = 0;
const createElm = function() {
const elm = document.createElement('div');
elm.id = 'app' + ++id;
document.body.appendChild(elm);
return elm;
};
/**
* 创建一个 Vue 的实例对象
* @param {Object} Compo 组件配置
* @param {Boolean=false} mounted 是否添加到 DOM 上
* @return {Object} vm
*/
exports.createVue = function(Compo, mounted = false) {
const elm = createElm();
return new Vue(Compo).$mount(mounted === false ? null : elm);
};
/**
* 创建一个测试组件实例
* @link http://vuejs.org/guide/unit-testing.html#Writing-Testable-Components
* @param {Object} Compo - 组件对象
* @param {Object} propsData - props 数据
* @param {Boolean=false} mounted - 是否添加到 DOM 上
* @return {Object} vm
*/
exports.createTest = function(Compo, propsData = {}, mounted = false) {
const elm = createElm();
const Ctor = Vue.extend(Compo);
return new Ctor({ propsData }).$mount(mounted === false ? null : elm);
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment