Browse Source

feat: rate组件开发

songqibin 5 years ago
parent
commit
ff7711e06b

+ 18 - 0
src/config.js

@@ -114,6 +114,15 @@ module.exports = {
           show: false,
           desc: '布局组件Col',
           author: 'undo'
+        },
+        {
+          name: 'row',
+          sort: 6,
+          cName: '布局-Row',
+          type: 'component',
+          show: false,
+          desc: '布局组件Row',
+          author: 'undo'
         }
       ]
     },
@@ -251,6 +260,15 @@ module.exports = {
           show: true,
           desc: '输入框组件',
           author: 'gxx158'
+        },
+        {
+          name: 'Rate',
+          sort: 2,
+          cName: '评分',
+          type: 'component',
+          show: true,
+          desc: '评分组件',
+          author: 'undo'
         }
       ]
     },

+ 36 - 0
src/config.ts

@@ -89,6 +89,33 @@ export const nav = [
         show: false,
         desc: '折叠面板-item',
         author: 'Ymm0008'
+      },
+      {
+        name: 'Layout',
+        sort: 4,
+        cName: '布局',
+        type: 'component',
+        show: true,
+        desc: '简便地创建布局',
+        author: 'undo'
+      },
+      {
+        name: 'col',
+        sort: 5,
+        cName: '布局-Col',
+        type: 'component',
+        show: false,
+        desc: '布局组件Col',
+        author: 'undo'
+      },
+      {
+        name: 'row',
+        sort: 6,
+        cName: '布局-Row',
+        type: 'component',
+        show: false,
+        desc: '布局组件Row',
+        author: 'undo'
       }
     ]
   },
@@ -226,6 +253,15 @@ export const nav = [
         show: true,
         desc: '数字输入框组件',
         author: 'szg2008'
+      },
+      {
+        name: 'Rate',
+        sort: 2,
+        cName: '评分',
+        type: 'component',
+        show: true,
+        desc: '评分组件',
+        author: 'undo'
       }
     ]
   },

+ 25 - 8
src/packages/layout/doc.md

@@ -1,6 +1,23 @@
-# Flex 布局
+# Layout 布局
 
-## 基本用法
+### 介绍
+
+用于快速进行布局
+
+### 安装
+
+``` javascript
+import { createApp } from 'vue';
+import { Row, Col } from '@nutui/nutui';
+
+const app = createApp();
+app.use(Row);
+app.use(Col);
+```
+
+## 代码演示
+
+### 基本用法
 
 ```html
 <nut-row>
@@ -59,7 +76,7 @@
 
 ```
 
-## 设置元素间距
+### 设置元素间距
 
 ```html
 <nut-row :gutter="10">
@@ -79,9 +96,9 @@
             
 ```
 
-## Flex布局
+### Flex布局
 
-### wrap(是否换行)
+#### wrap(是否换行)
 
 ```html
 <nut-row type="flex" flexWrap="nowrap" :gutter="10">
@@ -156,7 +173,7 @@
 
 ```
 
-### justify(主轴方向)
+#### justify(主轴方向)
 
 ```html
 <nut-row type="flex">
@@ -217,7 +234,7 @@
 
 ```
 
-### align(侧轴方向)
+#### align(侧轴方向)
 
 ```html
 <nut-row type="flex" gutter="10" align="flex-start">
@@ -256,7 +273,7 @@
 
 ```
 
-## 分栏偏移
+### 分栏偏移
 
 ```html
 <nut-row type="flex">

+ 79 - 0
src/packages/rate/demo.vue

@@ -0,0 +1,79 @@
+<template>
+  <div class="demo">
+    <h2>基本用法</h2>
+    <div>
+      <nut-cell>
+        <nut-rate v-model:value="state.val"></nut-rate>
+      </nut-cell>
+      <nut-cell> 当前分数:{{ state.val }}分 </nut-cell>
+    </div>
+
+    <h2>只读</h2>
+    <div>
+      <nut-cell>
+        <nut-rate v-model:value="state.val2" :readOnly="true"></nut-rate>
+      </nut-cell>
+      <nut-cell> 结果:{{ state.val2 }} </nut-cell>
+    </div>
+
+    <h2>自定义尺寸</h2>
+    <div>
+      <nut-cell>
+        <nut-rate :size="30"></nut-rate>
+      </nut-cell>
+    </div>
+
+    <h2>事件</h2>
+    <div>
+      <nut-cell>
+        <nut-rate @click="onClick"></nut-rate>
+      </nut-cell>
+      <nut-cell> 结果:{{ state.result }} </nut-cell>
+    </div>
+
+    <h2>自定义ICON</h2>
+    <div>
+      <nut-cell>
+        <nut-rate
+          :checkedIcon="state.icon1"
+          :uncheckedIcon="state.icon2"
+        ></nut-rate>
+      </nut-cell>
+    </div>
+  </div>
+</template>
+
+<script>
+import { reactive } from 'vue';
+import { createComponent } from '@/utils/create';
+const { createDemo } = createComponent('rate');
+export default createDemo({
+  setup() {
+    const state = reactive({
+      val: 4,
+      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")`
+    });
+    const onClick = idx => {
+      state.result = '您点击了第' + idx + '个!';
+    };
+    return {
+      state,
+      onClick
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.demo {
+  padding-left: 0;
+  padding-right: 0;
+}
+h4 {
+  padding: 0 10px;
+}
+</style>

+ 81 - 0
src/packages/rate/doc.md

@@ -0,0 +1,81 @@
+# Rate 评分
+
+### 介绍
+
+用于快速的评级操作,或对评价进行展示。
+
+### 安装
+
+``` javascript
+import { createApp } from 'vue';
+import { Rate } from '@nutui/nutui';
+
+const app = createApp();
+app.use(Rate);
+```
+
+## 代码演示
+
+### 基础用法
+
+```html
+<nut-rate 
+    v-model:value="state.val"
+>
+</nut-rate>
+```
+
+### 只读
+
+```html
+<nut-rate 
+    v-model:value="val"
+    :readOnly="true"
+>
+</nut-rate>
+```
+
+
+### 绑定事件
+
+```html
+<nut-rate 
+    @click="onClick"
+>
+</nut-rate>
+```
+
+### 自定义尺寸
+
+```html
+<nut-rate 
+    :size="35"
+>
+</nut-rate>
+```
+
+### 自定义ICON
+
+```html
+<nut-rate
+    :checkedIcon="`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")`"
+    :uncheckedIcon="`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")`"
+></nut-rate>
+```
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+| ----- | ----- | ----- | -----
+| total | star 总数 | Number | 5
+| value | 当前 star 数,可使用 v-model 双向绑定数据 | Number | 3
+| size | star 大小 | Number | 25
+| spacing | 两个star的间距 | Number | 20
+| readOnly | 是否只读 | Boolean | false
+| uncheckedIcon | 使用图标(未选中) | String | -
+| checkedIcon | 使用图标(选中) | String | -
+
+## Event
+| 字段 | 说明 | 回调参数 
+|----- | ----- | ----- 
+| click | 点击star时触发 | star的index

+ 33 - 0
src/packages/rate/index.scss

@@ -0,0 +1,33 @@
+@function toRGB($color) {
+  @return 'rgb(' + red($color) + ', ' + green($color) + ', ' + blue($color) +
+    ')';
+}
+
+@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;
+}
+
+@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");
+}
+
+.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);
+    }
+  }
+}

+ 92 - 0
src/packages/rate/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <div class="nut-rate">
+    <span
+      class="nut-rate-item"
+      :class="[{ 'nut-rate-active': n <= state.current }]"
+      v-for="n in total"
+      :key="n"
+      @click="onClick($event, n)"
+      :style="{
+        height: size + 'px',
+        width: size + 'px',
+        marginRight: spacing + 'px',
+        backgroundImage: n <= state.current ? checkedIcon : uncheckedIcon
+      }"
+    ></span>
+  </div>
+</template>
+<script lang="ts">
+import { toRefs, watch, reactive, inject } from 'vue';
+import { createComponent } from '@/utils/create';
+const { componentName, create } = createComponent('rate');
+
+export default create({
+  props: {
+    total: {
+      type: [String, Number],
+      default: 5
+    },
+    value: {
+      type: [String, Number],
+      default: 3
+    },
+    size: {
+      type: [String, Number],
+      default: 25
+    },
+    uncheckedIcon: {
+      type: String,
+      default: null
+    },
+    checkedIcon: {
+      type: String,
+      default: null
+    },
+    readOnly: {
+      type: Boolean,
+      default: false
+    },
+    spacing: {
+      type: [String, Number],
+      default: 20
+    }
+  },
+  setup(props, { emit, slots }) {
+    const { value } = toRefs(props);
+    const state = reactive({
+      current: props.value
+    });
+
+    const onClick = (e: Event, idx) => {
+      e.stopPropagation();
+      if (props.readOnly) {
+        emit('update:value', state.current);
+        emit('click', state.current);
+      } else {
+        if (state.current == idx) {
+          state.current = 0;
+        } else {
+          state.current = idx;
+        }
+        emit('update:value', state.current);
+        emit('click', state.current);
+      }
+    };
+    watch(
+      () => value.value,
+      newVal => {
+        state.current = newVal;
+      }
+    );
+
+    return {
+      state,
+      onClick
+    };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>