Browse Source

Merge pull request #66 from Leopoldthecoder/next

add message
FuryBean 9 năm trước cách đây
mục cha
commit
37ebca5ba7

+ 1 - 0
bin/build-entry.js

@@ -21,6 +21,7 @@ const install = function(Vue) {
   Vue.prototype.$confirm = MessageBox.confirm;
   Vue.prototype.$prompt = MessageBox.prompt;
   Vue.prototype.$notify = Notification;
+  Vue.prototype.$message = Message;
 };
 
 // auto install

+ 3 - 0
components.json

@@ -145,5 +145,8 @@
   ],
   "spinner": [
     "./packages/spinner/index.js"
+  ],
+  "message": [
+    "./packages/message/index.js"
   ]
 }

+ 214 - 0
examples/docs/message.md

@@ -0,0 +1,214 @@
+<script>
+  module.exports = {
+    methods: {
+      open() {
+        this.$message({
+          message: '这是一条消息提示'
+        });
+      },
+      
+      open2() {
+        this.$message({
+          message: '恭喜你,这是一条成功消息',
+          type: 'success'
+        });
+      },
+      
+      open3() {
+        this.$message({
+          message: '警告哦,这是一条警告消息',
+          type: 'warning'
+        });
+      },
+            
+      open4() {
+        this.$message({
+          message: '错了哦,这是一条错误消息',
+          type: 'error'
+        });
+      },
+                  
+      open5() {
+        this.$message({
+          showClose: true,
+          message: '恭喜你,这是一条成功消息'
+        });
+      },
+      
+      open6() {
+        this.$message({
+          showClose: true,
+          message: '警告哦,这是一条警告消息',
+          type: 'warning'
+        });
+      },
+            
+      open7() {
+        this.$message({
+          showClose: true,
+          message: '错了哦,这是一条错误消息',
+          type: 'error'
+        });
+      },
+      
+      open8() {
+        this.$message({
+          showClose: true,
+          message: '错了哦,这是一条错误消息',
+          type: 'error'
+        });
+      } 
+    }
+  };
+</script>
+
+<style>
+  .demo-box.demo-message {
+    .el-button + .el-button {
+      margin-left: 10px;
+    }
+  }
+</style>
+
+## 基本用法
+
+<div class="demo-box demo-message">
+  <el-button :plain="true" v-on:click.native="open">打开消息提示</el-button>
+</div>
+
+```html
+<template>
+  <el-button :plain="true" v-on:click.native="open">打开消息提示</el-button>
+</template>
+
+<script>
+  export default {
+    methods: {
+      open() {
+        this.$message({
+          message: '这是一条消息提示'
+        });
+      }
+    }
+  }
+</script>
+```
+
+## 不同状态
+<div class="demo-box demo-message">
+  <el-button :plain="true" v-on:click.native="open2">成功</el-button>
+  <el-button :plain="true" v-on:click.native="open3">警告</el-button>
+  <el-button :plain="true" v-on:click.native="open4">错误</el-button>
+</div>
+
+```html
+<template>
+  <el-button :plain="true" v-on:click.native="open2">成功</el-button>
+  <el-button :plain="true" v-on:click.native="open3">警告</el-button>
+  <el-button :plain="true" v-on:click.native="open4">错误</el-button>
+</template>
+
+<script>
+  export default {
+    methods: {
+      open2() {
+        this.$message({
+          message: '恭喜你,这是一条成功消息',
+          type: 'success'
+        });
+      },
+      
+      open3() {
+        this.$message({
+          message: '警告哦,这是一条警告消息',
+          type: 'warning'
+        });
+      },
+            
+      open4() {
+        this.$message({
+          message: '错了哦,这是一条错误消息',
+          type: 'error'
+        });
+      }
+    }
+  }
+</script>
+```
+
+## 可关闭
+<div class="demo-box demo-message">
+  <el-button :plain="true" v-on:click.native="open5">消息</el-button>
+  <el-button :plain="true" v-on:click.native="open6">成功</el-button>
+  <el-button :plain="true" v-on:click.native="open7">警告</el-button>
+  <el-button :plain="true" v-on:click.native="open8">错误</el-button>
+</div>
+
+```html
+<template>
+  <el-button :plain="true" v-on:click.native="open5">消息</el-button>
+  <el-button :plain="true" v-on:click.native="open6">成功</el-button>
+  <el-button :plain="true" v-on:click.native="open7">警告</el-button>
+  <el-button :plain="true" v-on:click.native="open8">错误</el-button>
+</template>
+
+<script>
+  export default {
+    methods: {
+      open5() {
+        this.$message({
+          showClose: true,
+          message: '恭喜你,这是一条成功消息'
+        });
+      },
+      
+      open6() {
+        this.$message({
+          showClose: true,
+          message: '警告哦,这是一条警告消息',
+          type: 'warning'
+        });
+      },
+            
+      open7() {
+        this.$message({
+          showClose: true,
+          message: '错了哦,这是一条错误消息',
+          type: 'error'
+        });
+      },
+      
+      open8() {
+        this.$message({
+          showClose: true,
+          message: '错了哦,这是一条错误消息',
+          type: 'error'
+        });
+      }
+    }
+  }
+</script>
+```
+
+## 全局方法
+
+element 为 Vue.prototype 添加了全局方法 $message。因此在 vue instance 中可以采用本页面中的方式调用 `Message`。
+
+## 单独引用
+
+单独引入 `Message`:
+
+```javascript
+import { Message } from 'element-ui';
+```
+
+此时调用方法为 `Message(options)`。
+
+## API
+| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
+|---------- |-------------- |---------- |--------------------------------  |-------- |
+| message | 消息文字 | string | | |
+| type | 主题 | string | 'success', 'warning', 'info', 'error' | 'info' |
+| duration | 显示时间, 毫秒。设为 0 则不会自动关闭 | number | | 3000 |
+| showClose | 是否显示关闭按钮 | boolean | | false |
+| onClose | 关闭时的回调函数, 参数为被关闭的 message 实例 | function | | |

+ 60 - 36
examples/docs/select.md

@@ -4,36 +4,36 @@
       return {
         options: [{
           value: '选项1',
-          label: '标签1'
+          label: '黄金糕'
         }, {
           value: '选项2',
-          label: '标签2'
+          label: '双皮奶'
         }, {
           value: '选项3',
-          label: '标签3'
+          label: '蚵仔煎'
         }, {
           value: '选项4',
-          label: '标签4'
+          label: '龙须面'
         }, {
           value: '选项5',
-          label: '标签5'
+          label: '北京烤鸭'
         }],
         options2: [{
           value: '选项1',
-          label: '标签1'
+          label: '黄金糕'
         }, {
           value: '选项2',
-          label: '标签2',
+          label: '双皮奶',
           disabled: true
         }, {
           value: '选项3',
-          label: '标签3'
+          label: '蚵仔煎'
         }, {
           value: '选项4',
-          label: '标签4'
+          label: '龙须面'
         }, {
           value: '选项5',
-          label: '标签5'
+          label: '北京烤鸭'
         }],
         options3: [{
           label: '分组1',
@@ -59,39 +59,58 @@
         }],
         options4: [{
           value: '选项1',
-          label: '标签1'
+          label: '黄金糕'
         }, {
           value: '选项2',
-          label: '标签2'
+          label: '双皮奶'
         }, {
           value: '选项3',
-          label: '标签3'
+          label: '蚵仔煎'
         }, {
           value: '选项4',
-          label: '标签4'
+          label: '龙须面'
         }, {
           value: '选项5',
-          label: '标签5'
+          label: '北京烤鸭'
         }, {
           value: '选项6',
-          label: '标签6'
+          label: '炸酱面'
         }, {
           value: '选项7',
-          label: '标签7'
+          label: '羊蝎子'
         }, {
           value: '选项8',
-          label: '标签8'
+          label: '肉夹馍'
         }, {
           value: '选项9',
-          label: '标签9'
+          label: '回锅肉'
         }, {
           value: '选项10',
-          label: '标签10'
+          label: '小笼包'
         }, {
           value: '选项11',
-          label: '标签11'
+          label: '红烧肉'
         }],
         options5: [],
+        cities: [{
+          value: 'Beijing',
+          label: '北京'
+        }, {
+          value: 'Shanghai',
+          label: '上海'
+        }, {
+          value: 'Nanjing',
+          label: '南京'
+        }, {
+          value: 'Chengdu',
+          label: '成都'
+        }, {
+          value: 'Shenzhen',
+          label: '深圳'
+        }, {
+          value: 'Guangzhou',
+          label: '广州'
+        }],
         value: '',
         value2: '',
         value3: '',
@@ -392,10 +411,11 @@
 
 <el-select v-model="value6">
   <el-option
-    v-for="item in options"
+    v-for="item in cities"
     :label="item.label"
     :value="item.value">
-    <span>label: {{ item.label }}, value: {{ item.value }}</span>
+    <span style="float: left">{{ item.label }}</span>
+    <span style="float: right; color: #8492a6; font-size: 13px">{{ item.value }}</span>
   </el-option>
 </el-select>
 
@@ -403,10 +423,11 @@
 <template>
   <el-select v-model="value6">
     <el-option
-      v-for="item in options"
+      v-for="item in cities"
       :label="item.label"
       :value="item.value">
-      <span>label: {{ item.label }}, value: {{ item.value }}</span>
+      <span style="float: left">{{ item.label }}</span>
+      <span style="float: right; color: #8492a6; font-size: 13px">{{ item.value }}</span>
     </el-option>
   </el-select>
 </template>
@@ -415,21 +436,24 @@
   export default {
     data() {
       return {
-        options: [{
-          value: '选项1',
-          label: '标签1'
+        cities: [{
+          value: 'Beijing',
+          label: '北京'
         }, {
-          value: '选项2',
-          label: '标签2'
+          value: 'Shanghai',
+          label: '上海'
         }, {
-          value: '选项3',
-          label: '标签3'
+          value: 'Nanjing',
+          label: '南京'
         }, {
-          value: '选项4',
-          label: '标签4'
+          value: 'Chengdu',
+          label: '成都'
         }, {
-          value: '选项5',
-          label: '标签5'
+          value: 'Shenzhen',
+          label: '深圳'
+        }, {
+          value: 'Guangzhou',
+          label: '广州'
         }],
         value6: ''
       }

+ 6 - 0
examples/nav.config.json

@@ -81,6 +81,12 @@
         "title": "notification 通知",
         "description": "悬浮出现在页面右上角, 显示全局的通知提醒消息"
       },
+      {
+        "path": "/message",
+        "name": "消息提示 (message)",
+        "title": "message 消息提示",
+        "description": "对用户的操作进行反馈提示,包含成功、反馈或错误等消息提示"
+      },
       {
         "path": "/loading",
         "name": "加载 (loading)",

+ 1 - 1
package.json

@@ -48,7 +48,7 @@
     "vue-loader": "^9.3.2",
     "vue": "^2.0.0-rc.1",
     "vue-markdown-loader": "^0.4.0",
-    "vue-popup": "^0.2.1",
+    "vue-popup": "^0.2.2",
     "vue-router": "^2.0.0-beta.2"
   }
 }

+ 1 - 1
packages/dialog/package.json

@@ -12,6 +12,6 @@
   "author": "elemefe",
   "license": "MIT",
   "devDependencies": {
-    "vue-popup": "^0.2.1"
+    "vue-popup": "^0.2.2"
   }
 }

+ 1 - 1
packages/message-box/package.json

@@ -12,6 +12,6 @@
   "author": "elemefe",
   "license": "MIT",
   "dependencies": {
-    "vue-popup": "^0.2.1"
+    "vue-popup": "^0.2.2"
   }
 }

+ 31 - 0
packages/message/cooking.conf.js

@@ -0,0 +1,31 @@
+var cooking = require('cooking');
+var path = require('path');
+
+cooking.set({
+  entry: {
+    index: path.join(__dirname, 'index.js')
+  },
+  dist: path.join(__dirname, 'lib'),
+  template: false,
+  format: 'umd',
+  moduleName: 'ElMessage',
+  extractCSS: 'style.css',
+
+  extends: ['vue', 'saladcss']
+});
+
+cooking.add('resolve.alias', {
+  'main': path.join(__dirname, '../../src'),
+  'packages': path.join(__dirname, '../../packages')
+});
+
+cooking.add('externals', {
+  vue: {
+    root: 'Vue',
+    commonjs: 'vue',
+    commonjs2: 'vue',
+    amd: 'vue'
+  }
+});
+
+module.exports = cooking.resolve();

+ 3 - 0
packages/message/index.js

@@ -0,0 +1,3 @@
+import Message from './src/main.js';
+
+module.exports = Message;

+ 15 - 0
packages/message/package.json

@@ -0,0 +1,15 @@
+{
+  "name": "el-message",
+  "version": "0.0.0",
+  "description": "A message component for Vue.js.",
+  "keywords": [
+    "element",
+    "vue",
+    "component"
+  ],
+  "main": "./lib/index.js",
+  "repository": "https://github.com/element-component/element/tree/master/packages/message",
+  "author": "elemefe",
+  "license": "MIT",
+  "dependencies": {}
+}

+ 57 - 0
packages/message/src/main.js

@@ -0,0 +1,57 @@
+import Vue from 'vue';
+let MessageConstructor = Vue.extend(require('./main.vue'));
+
+let instance;
+let instances = [];
+let seed = 1;
+
+var Message = function(options) {
+  options = options || {};
+  let userOnClose = options.onClose;
+  let id = 'message_' + seed++;
+
+  options.onClose = function() {
+    Message.close(id, userOnClose);
+  };
+
+  instance = new MessageConstructor({
+    data: options
+  });
+  instance.id = id;
+  instance.vm = instance.$mount();
+  document.body.appendChild(instance.vm.$el);
+  instance.vm.visible = true;
+  instance.dom = instance.vm.$el;
+
+  let topDist = 0;
+  for (let i = 0, len = instances.length; i < len; i++) {
+    topDist += instances[i].$el.offsetHeight + 20;
+  }
+  topDist += 20;
+  instance.top = topDist;
+  instances.push(instance);
+};
+
+Message.close = function(id, userOnClose) {
+  let index;
+  let removedHeight;
+  for (var i = 0, len = instances.length; i < len; i++) {
+    if (id === instances[i].id) {
+      if (typeof userOnClose === 'function') {
+        userOnClose(instances[i]);
+      }
+      index = i;
+      removedHeight = instances[i].dom.offsetHeight;
+      instances.splice(i, 1);
+      break;
+    }
+  }
+
+  if (len > 1) {
+    for (i = index; i < len - 1 ; i++) {
+      instances[i].dom.style.top = parseInt(instances[i].dom.style.top, 10) - removedHeight - 20 + 'px';
+    }
+  }
+};
+
+export default Message;

+ 81 - 0
packages/message/src/main.vue

@@ -0,0 +1,81 @@
+<template>
+  <transition name="el-message-fade">
+    <div class="el-message" v-show="visible" :style="{ top: top ? top + 'px' : 'auto' }" @mouseenter="clearTimer" @mouseleave="startTimer">
+      <i class="el-message__icon" :class="[ typeClass ]"></i>
+      <div class="el-message__group">
+        <p>{{ message }}</p>
+        <div v-if="showClose" class="el-message__closeBtn el-icon-close" @click="handleClose"></div>
+      </div>
+    </div>
+  </transition>
+</template>
+
+<script type="text/babel">
+  let typeMap = {
+    success: 'circle-check',
+    info: 'information',
+    warning: 'warning',
+    error: 'circle-cross'
+  };
+
+  export default {
+    data() {
+      return {
+        visible: false,
+        message: '',
+        duration: 3000,
+        type: 'info',
+        onClose: null,
+        showClose: false,
+        closed: false,
+        top: null,
+        timer: null
+      };
+    },
+
+    computed: {
+      typeClass() {
+        return `el-icon-${ typeMap[this.type] }`;
+      }
+    },
+
+    watch: {
+      closed(newVal) {
+        if (newVal) {
+          this.visible = false;
+          this.$el.addEventListener('transitionend', () => {
+            this.$destroy(true);
+            this.$el.parentNode.removeChild(this.$el);
+          });
+        }
+      }
+    },
+
+    methods: {
+      handleClose() {
+        this.closed = true;
+        if (typeof this.onClose === 'function') {
+          this.onClose();
+        }
+      },
+
+      clearTimer() {
+        clearTimeout(this.timer);
+      },
+
+      startTimer() {
+        if (this.duration > 0) {
+          this.timer = setTimeout(() => {
+            if (!this.closed) {
+              this.handleClose();
+            }
+          }, this.duration);
+        }
+      }
+    },
+
+    mounted() {
+      this.startTimer();
+    }
+  };
+</script>

+ 7 - 1
packages/select/src/select.vue

@@ -281,6 +281,7 @@
 
       visible(val) {
         if (!val) {
+          this.$refs.reference.$el.querySelector('input').blur();
           this.$el.querySelector('.el-input__icon').classList.remove('is-reverse');
           this.broadcast('select-dropdown', 'destroyPopper');
           if (this.$refs.input) {
@@ -423,6 +424,9 @@
       },
 
       toggleMenu() {
+        if (this.filterable && this.query === '' && this.visible) {
+          return;
+        }
         if (!this.disabled) {
           this.visible = !this.visible;
           if (this.remote && this.visible) {
@@ -472,7 +476,9 @@
       },
 
       selectOption() {
-        this.handleOptionSelect(this.options[this.hoverIndex]);
+        if (this.options[this.hoverIndex]) {
+          this.handleOptionSelect(this.options[this.hoverIndex]);
+        }
       },
 
       deleteSelected(event) {

+ 1 - 0
packages/theme-default/src/index.css

@@ -15,6 +15,7 @@
 @import "./popover.css";
 @import "./tooltip.css";
 @import "./autocomplete.css";
+@import "./message.css";
 @import "./message-box.css";
 @import "./date-picker.css";
 @import "./time-picker.css";

+ 72 - 0
packages/theme-default/src/message.css

@@ -0,0 +1,72 @@
+@charset "UTF-8";
+@import "./common/var.css";
+
+@component-namespace el {
+
+  @b message {
+    box-shadow:0 2px 4px 0 rgba(0, 0, 0, .12), 0 0 6px 0 rgba(0, 0, 0, .04);
+    width: 300px;
+    padding: 10px 12px;
+    box-sizing: border-box;
+    border-radius: 2px;
+    position: fixed;
+    left: 50%;
+    transform: translateX(-50%);
+    background-color: #fff;
+    transition: opacity 0.3s, top 0.4s;
+    overflow: hidden;
+    z-index: 1000;
+
+    @e group {
+      margin-left: 28px;
+      position: relative;
+
+      & p {
+        font-size: 14px;
+        line-height: 20px;
+        margin: 0 20px 0 0;
+        color: #8492a6;
+        text-align: justify;
+      }
+    }
+
+    @e icon {
+      size: 20px;
+      font-size: 20px;
+      float: left;
+      position: relative;
+    }
+
+    @e closeBtn {
+      position: absolute 3px 0 * *;
+      cursor: pointer;
+      color: #C0CCDA;
+      font-size: 14px;
+
+      &:hover {
+        color: #99A9BF;
+      }
+    }
+
+    & .el-icon-circle-check {
+      color: #13ce66;
+    }
+
+    & .el-icon-circle-cross {
+      color: #ff4949;
+    }
+
+    & .el-icon-information {
+      color: #50bfff;
+    }
+
+    & .el-icon-warning {
+      color: #f7ba2a;
+    }
+  }
+
+  .el-message-fade-enter,
+  .el-message-fade-leave-active {
+    opacity: 0;
+  }
+}

+ 5 - 1
src/index.js

@@ -47,6 +47,7 @@ import Col from '../packages/col/index.js';
 import Upload from '../packages/upload/index.js';
 import Progress from '../packages/progress/index.js';
 import Spinner from '../packages/spinner/index.js';
+import Message from '../packages/message/index.js';
 
 const install = function(Vue) {
   if (install.installed) return;
@@ -97,6 +98,7 @@ const install = function(Vue) {
   Vue.component(Upload.name, Upload);
   Vue.component(Progress.name, Progress);
   Vue.component(Spinner.name, Spinner);
+  Vue.component(Message.name, Message);
 
   Vue.use(Loading);
 
@@ -105,6 +107,7 @@ const install = function(Vue) {
   Vue.prototype.$confirm = MessageBox.confirm;
   Vue.prototype.$prompt = MessageBox.prompt;
   Vue.prototype.$notify = Notification;
+  Vue.prototype.$message = Message;
 };
 
 // auto install
@@ -162,5 +165,6 @@ module.exports = {
   Col,
   Upload,
   Progress,
-  Spinner
+  Spinner,
+  Message
 };