Browse Source

feat: 评分组件增加自定义颜色/可选择半星功能

yushuang24 5 years ago
parent
commit
b910e89db6

BIN
src/assets/img/checked.png


BIN
src/assets/img/unchecked.png


+ 4 - 0
src/assets/svg/rate-default-img.svg

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path d="M18,27.4l-7.9,4.1c-0.7,0.4-1.6,0.1-2-0.6c-0.2-0.3-0.2-0.6-0.2-1l1.5-8.8l0,0
+	L3.1,15c-0.6-0.6-0.6-1.5,0-2.1c0.2-0.2,0.5-0.4,0.9-0.4l8.8-1.3l0,0l3.9-8c0.4-0.7,1.3-1,2-0.7c0.3,0.1,0.5,0.4,0.7,0.7l3.9,8l0,0
+	l8.8,1.3c0.8,0.1,1.4,0.9,1.3,1.7c0,0.3-0.2,0.6-0.4,0.9l-6.4,6.2l0,0l1.5,8.8c0.1,0.8-0.4,1.6-1.2,1.7c-0.3,0.1-0.7,0-1-0.2
+	L18,27.4L18,27.4z" fill-rule="evenodd"/></svg>

+ 55 - 43
src/packages/actionsheet/actionsheet.scss

@@ -1,64 +1,76 @@
 @import '../../styles/animation/fade';
 @import '../../styles/animation/slide-up';
+
 .nut-actionsheet-mask {
-  @include fix-fullscreen();
+	@include fix-fullscreen();
 }
+
 .nut-actionsheet-panel {
-  position: fixed;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  width: 100%;
-  max-height: 80%;
-  overflow: auto;
-  z-index: $zindex-actionsheet;
-  background-color: $body-background;
+	position: fixed;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	width: 100%;
+	max-height: 80%;
+	overflow: auto;
+	z-index: $zindex-actionsheet;
+	background-color: $body-background;
 }
+
 .nut-actionsheet-modal {
-  padding: 10px;
-  margin: 0;
-  text-align: center;
-  background-color: #fff;
-  border-bottom: 1px solid $light-color;
-  .nut-actionsheet-title,
-  .nut-actionsheet-sub-title {
-    padding: 5px 0;
-  }
-  .nut-actionsheet-title {
-    font-size: $font-size-base;
-    color: $title-color;
-  }
-  .nut-actionsheet-sub-title {
-    font-size: $font-size-small;
-    color: $title-color;
-    margin-inline-start: 0px;
-  }
+	padding: 10px;
+	margin: 0;
+	text-align: center;
+	background-color: #fff;
+	border-bottom: 1px solid $light-color;
+
+	.nut-actionsheet-title,
+	.nut-actionsheet-sub-title {
+		padding: 5px 0;
+	}
+
+	.nut-actionsheet-title {
+		font-size: $font-size-base;
+		color: $title-color;
+	}
+
+	.nut-actionsheet-sub-title {
+		font-size: $font-size-small;
+		color: $title-color;
+		margin-inline-start: 0;
+	}
 }
+
 .nut-actionsheet-menu {
-  list-style: none;
-  padding: 0;
-  margin: 0;
+	list-style: none;
+	padding: 0;
+	margin: 0;
 }
+
 .nut-actionsheet-cancel,
 .nut-actionsheet-item {
-  height: 24px;
-  padding: 10px;
-  line-height: 24px;
-  font-size: $font-size-base;
-  color: $title-color;
-  text-align: center;
-  background-color: #fff;
+	height: 24px;
+	padding: 10px;
+	line-height: 24px;
+	font-size: $font-size-base;
+	color: $title-color;
+	text-align: center;
+	background-color: #fff;
 }
+
 .nut-actionsheet-item {
-  border-bottom: 1px solid $light-color;
+	border-bottom: 1px solid $light-color;
 }
+
 .nut-actionsheet-item-active {
-  color: $primary-color;
+	color: $primary-color;
 }
+
 .nut-actionsheet-item-disabled {
-  color: #e1e1e1;
+	color: #e1e1e1;
 }
+
 .nut-actionsheet-cancel {
-  margin-top: 5px;
-  border-top: 1px solid $light-color;
+	margin-top: 5px;
+	border-top: 1px solid $light-color;
 }

+ 12 - 1
src/packages/rate/__test__/rate.spec.js

@@ -26,5 +26,16 @@ describe('Rate.vue', () => {
         wrapper.findAll('.nut-rate-item').at(2).trigger('click');
         expect(wrapper.findAll('.nut-rate-item').at(2).is('.nut-rate-active')).toBe(true)
     });
-
+    
+    //只读状态点击
+    it('只读点击评分', () => {
+        wrapper.setProps({ readOnly: true });
+        wrapper.findAll('.nut-rate-item').at(2).trigger('click');
+        expect(wrapper.findAll('.nut-rate-item').at(2).is('.nut-rate-active')).toBe(true)
+    });
+    //点击半星
+    it('点击半星', () => {
+        wrapper.findAll('.halfstar_contain').at(2).trigger('click');
+        expect(wrapper.findAll('.halfstar_contain').at(2).is('.nut-rate-half-active')).toBe(true)
+    });
 });

+ 25 - 7
src/packages/rate/demo.vue

@@ -27,6 +27,17 @@
       </nut-cell>
     </div>
 
+    <h4>自定义颜色</h4>
+    <div>
+      <nut-cell>
+        <span slot="title">
+          <nut-rate :checkedColor="checkedColor" v-model="val3" >
+            <span class="fontcolor" slot="nut-rate-font">{{ val3 }},满意</span>
+          </nut-rate>
+        </span>
+      </nut-cell>
+    </div>
+
     <h4>事件</h4>
     <div>
       <nut-cell>
@@ -50,12 +61,14 @@
 export default {
   data() {
     return {
-      val: 4,
-      val2: 2,
+      val: 4.5,
+      val2: 2.5,
+      val3:3.5,
       result: '',
       result2: '',
-      icon1: `url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='rgb(255,0,0)' d='M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zM6.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm2.16 3H4.34a6 6 0 0 0 11.32 0z'/%3E%3C/svg%3E")`,
-      icon2: `url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='rgb(255,0,0)' d='M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM6.5 9a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm7 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM7 13h6a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2z'/%3E%3C/svg%3E")`
+      checkedColor:'#FFC200',
+      icon1: require('./../../assets/img/checked.png'),
+      icon2: require('./../../assets/img/unchecked.png')
     };
   },
 
@@ -72,10 +85,15 @@ export default {
 
 <style lang="scss" scoped>
 .demo {
-  padding-left: 0;
-  padding-right: 0;
+	padding-left: 0;
+	padding-right: 0;
 }
+
 h4 {
-  padding: 0 10px;
+	padding: 0 10px;
+}
+
+.fontcolor {
+	color: #ffc200;
 }
 </style>

+ 14 - 2
src/packages/rate/doc.md

@@ -39,6 +39,15 @@
 </nut-rate>
 ```
 
+自定义颜色
+
+```html
+<nut-rate 
+    :checkedColor="checkedColor"
+>
+</nut-rate>
+```
+
 自定义ICON
 
 ```html
@@ -56,8 +65,8 @@ export default {
             val2:2,
             result:'',
             result2:'',
-            icon1:`url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='rgb(255,0,0)' d='M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zM6.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm7 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm2.16 3H4.34a6 6 0 0 0 11.32 0z'/%3E%3C/svg%3E")`,
-            icon2:`url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='rgb(255,0,0)' d='M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM6.5 9a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm7 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM7 13h6a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2z'/%3E%3C/svg%3E")`
+            icon1: require('./../../assets/img/checked.png'),
+            icon2: require('./../../assets/img/unchecked.png')
         }
     },
    
@@ -83,6 +92,9 @@ export default {
 | readOnly | 是否只读 | Boolean | false
 | uncheckedIcon | 使用图标(未选中) | String | -
 | checkedIcon | 使用图标(选中) | String | -
+| checkedColor | 选中star颜色 | String | -
+| showHalf | 是否显示文字 | Boolean | true
+
 
 ## Event
 | 字段 | 说明 | 回调参数 

+ 43 - 28
src/packages/rate/rate.scss

@@ -1,32 +1,47 @@
-@function toRGB($color) {
-  @return 'rgb(' + red($color) + ', ' + green($color) + ', ' + blue($color) + ')';
-}
+.nut-rate {
+	.nut-rate-item {
+		display: inline-block;
+		position: relative;
+		vertical-align: bottom;
+		width: 30px;
+		height: 30px;
+		margin-right: 15px;
+		color: #f0f0f0;
+		background-size: cover;
 
-@mixin nut-rate-bg($color) {
-  $svgColor: toRGB($color);
-  background: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='16' height='16' viewBox='0 0 16 16'%3E %3Cpath fill='#{$svgColor}' d='M16 6.204l-5.528-0.803-2.472-5.009-2.472 5.009-5.528 0.803 4 3.899-0.944 5.505 4.944-2.599 4.944 2.599-0.944-5.505 4-3.899zM8 11.773l-3.492 1.836 0.667-3.888-2.825-2.753 3.904-0.567 1.746-3.537 1.746 3.537 3.904 0.567-2.825 2.753 0.667 3.888-3.492-1.836z'%3E%3C/path%3E %3C/svg%3E")
-    center no-repeat;
-}
+		svg {
+			vertical-align: top;
+			width: 100%;
+			height: 100%;
+			fill: currentColor;
+		}
 
-@mixin nut-rate-active-bg($color) {
-  $svgColor: toRGB($color);
-  background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='16' height='16' viewBox='0 0 16 16'%3E %3Cpath fill='#{$svgColor}' d='M16 6.204l-5.528-0.803-2.472-5.009-2.472 5.009-5.528 0.803 4 3.899-0.944 5.505 4.944-2.599 4.944 2.599-0.944-5.505 4-3.899z'%3E%3C/path%3E %3C/svg%3E");
-}
+		.halfstar_contain {
+			width: 50%;
+			height: 100%;
+			display: inline-block;
+			position: absolute;
+			top: 0;
+			left: 0;
+			overflow: hidden;
+			color: #f0f0f0;
 
-.nut-rate {
-  .nut-rate-item {
-    display: inline-block;
-    vertical-align: bottom;
-    width: 30px;
-    height: 30px;
-    margin-right: 15px;
-    @include nut-rate-bg($primary-color);
-    background-size: cover;
-    &:last-child {
-      margin-right: 0;
-    }
-    &.nut-rate-active {
-      @include nut-rate-active-bg($primary-color);
-    }
-  }
+			svg.halfstar {
+				height: 100%;
+				width: 200%;
+			}
+
+			&.nut-rate-half-active {
+				color: $primary-color;
+			}
+		}
+
+		&:last-child {
+			margin-right: 0;
+		}
+
+		&.nut-rate-active {
+			color: $primary-color;
+		}
+	}
 }

+ 50 - 5
src/packages/rate/rate.vue

@@ -9,11 +9,25 @@
       :style="{
         height: size + 'px',
         width: size + 'px',
+        color:`${n <= current ? checkedColor : ''}`,
         marginRight: spacing + 'px',
-        backgroundImage: n <= current ? checkedIcon : uncheckedIcon
+        backgroundImage: n <= current ? `url(${checkedIcon})` : `url(${uncheckedIcon})`,
       }"
     >
+      <i v-if="!checkedIcon">
+        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path d="M18,27.4l-7.9,4.1c-0.7,0.4-1.6,0.1-2-0.6c-0.2-0.3-0.2-0.6-0.2-1l1.5-8.8l0,0
+	      L3.1,15c-0.6-0.6-0.6-1.5,0-2.1c0.2-0.2,0.5-0.4,0.9-0.4l8.8-1.3l0,0l3.9-8c0.4-0.7,1.3-1,2-0.7c0.3,0.1,0.5,0.4,0.7,0.7l3.9,8l0,0
+	      l8.8,1.3c0.8,0.1,1.4,0.9,1.3,1.7c0,0.3-0.2,0.6-0.4,0.9l-6.4,6.2l0,0l1.5,8.8c0.1,0.8-0.4,1.6-1.2,1.7c-0.3,0.1-0.7,0-1-0.2
+	      L18,27.4L18,27.4z" fill-rule="evenodd"/></svg>
+        <i v-if="showHalf" class="halfstar_contain" @click="halfClick($event, n)" :class="[{ 'nut-rate-half-active': halfStarClick ? n <= current+1 : n <= current}]" :style="{color:`${halfStarClick ? (n <= current+1 ? checkedColor : '') : (n <= current ? checkedColor : '')}`}">
+          <svg class="halfstar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path d="M18,27.4l-7.9,4.1c-0.7,0.4-1.6,0.1-2-0.6c-0.2-0.3-0.2-0.6-0.2-1l1.5-8.8l0,0
+	        L3.1,15c-0.6-0.6-0.6-1.5,0-2.1c0.2-0.2,0.5-0.4,0.9-0.4l8.8-1.3l0,0l3.9-8c0.4-0.7,1.3-1,2-0.7c0.3,0.1,0.5,0.4,0.7,0.7l3.9,8l0,0
+	        l8.8,1.3c0.8,0.1,1.4,0.9,1.3,1.7c0,0.3-0.2,0.6-0.4,0.9l-6.4,6.2l0,0l1.5,8.8c0.1,0.8-0.4,1.6-1.2,1.7c-0.3,0.1-0.7,0-1-0.2
+	        L18,27.4L18,27.4z" fill-rule="evenodd"/></svg>
+        </i>
+      </i>
     </span>
+    <slot name="nut-rate-font"></slot>
   </div>
 </template>
 <script>
@@ -48,26 +62,57 @@ export default {
     spacing: {
       type: [String, Number],
       default: 20
+    },
+    checkedColor: {
+      type: [String],
+      default: null
+    },
+    showHalf:{
+      type: Boolean,
+      default: true
     }
   },
   data() {
     return {
-      current: 3
+      current: 3,
+      defaultImage:require('./../../assets/svg/rate-default-img.svg'),
+      halfStarClick:false
     };
   },
   created() {
-    this.current = this.value;
+    if(parseInt(this.value) === parseFloat(this.value)){
+       this.current = this.value;
+    }else{
+       this.current = this.value;
+       this.showHalf = true;
+       this.halfStarClick = true;
+    }
   },
   methods: {
     onClick($event, idx) {
+     
       if (this.readOnly) {
-        this.$emit('input', this.current);
-        this.$emit('click', this.current);
+        return
       } else {
+        this.halfStarClick=false;
         this.current = idx;
         this.$emit('input', idx);
         this.$emit('click', idx);
       }
+    },
+    halfClick($event, idx){
+      $event.stopPropagation();
+      if(!this.showHalf){
+        return
+      }
+      if (this.readOnly) {
+        return
+      } else {
+        this.halfStarClick=true;
+        this.current = idx-0.5;
+        this.$emit('input', idx-0.5);
+        this.$emit('click', idx-0.5);
+      }
     }
   }
 };