Browse Source

fix: merge conflict

zongyue3 5 years ago
parent
commit
4bd60ce9d7

+ 36 - 0
src/config.js

@@ -96,6 +96,33 @@ module.exports = {
           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'
         }
       ]
     },
@@ -243,6 +270,15 @@ module.exports = {
           sort: 3,
           show: true,
           author: 'zongyue3'
+        },
+        {
+          name: 'Rate',
+          sort: 2,
+          cName: '评分',
+          type: 'component',
+          show: true,
+          desc: '评分组件',
+          author: 'undo'
         }
       ]
     },

+ 272 - 0
src/config.ts

@@ -0,0 +1,272 @@
+export const versions = [
+  { name: '1.x', link: '/1x/' },
+  { name: '2.x', link: '/' },
+  { name: '3.x', link: '/3x/' }
+];
+
+export const header = [
+  {
+    name: 'guide',
+    cName: '指南',
+    path: '/'
+  },
+  {
+    name: '/',
+    cName: '组件',
+    path: '/'
+  },
+  {
+    name: 'example',
+    cName: '示例',
+    path: '/'
+  },
+  {
+    name: 'resource',
+    cName: '资源',
+    path: '/resource'
+  }
+];
+
+export const docs = {
+  name: '指南',
+  packages: [
+    {
+      name: 'intro',
+      cName: '介绍',
+      show: true
+    },
+    {
+      name: 'start',
+      cName: '快速上手',
+      show: true
+    },
+    {
+      name: 'theme',
+      cName: '主题定制',
+      show: true
+    },
+    {
+      name: 'international',
+      cName: '国际化',
+      show: true
+    },
+    {
+      name: 'https://github.com/jdf2e/nutui/releases',
+      cName: '更新日志',
+      show: true,
+      isLink: true
+    }
+  ]
+};
+
+export const nav = [
+  {
+    name: '布局组件',
+    packages: [
+      {
+        name: 'Button',
+        sort: 1,
+        cName: '按钮组件',
+        type: 'component',
+        show: true,
+        desc: '按钮用于触发一个操作,如提交表单。',
+        author: 'richard1015'
+      },
+      {
+        name: 'collapse',
+        sort: 2,
+        cName: '折叠面板',
+        type: 'component',
+        show: true,
+        desc: '折叠面板',
+        author: 'Ymm0008'
+      },
+      {
+        name: 'collapse',
+        sort: 3,
+        cName: '折叠面板-item',
+        type: 'component',
+        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'
+      }
+    ]
+  },
+  {
+    name: '操作反馈',
+    packages: [
+      {
+        name: 'BackTop',
+        sort: '1',
+        cName: '回到顶部',
+        type: 'component',
+        show: true,
+        desc: '较长页面快捷回到顶部',
+        author: 'liqiong43'
+      }
+    ]
+  },
+  {
+    name: '基础组件',
+    packages: [
+      {
+        name: 'Temp',
+        sort: 1,
+        cName: '模板组件',
+        type: 'component',
+        show: true,
+        desc: '组件模板示例',
+        author: 'richard1015'
+      },
+      {
+        name: 'Cell',
+        sort: 1,
+        cName: '单元格组件',
+        type: 'component',
+        show: true,
+        desc: '展示列表',
+        author: 'richard1015'
+      },
+      {
+        name: 'Uploader',
+        sort: 2,
+        cName: '上传组件',
+        type: 'component',
+        show: true,
+        desc: '上传文件、图片',
+        author: 'richard1015'
+      },
+      {
+        name: 'Icon',
+        sort: 3,
+        cName: '图标组件',
+        type: 'component',
+        show: true,
+        desc: '图标',
+        author: 'richard1015'
+      },
+      {
+        name: 'Price',
+        sort: 4,
+        cName: '价格组件',
+        type: 'component',
+        show: true,
+        desc: '价格组件',
+        author: 'ailululu'
+      },
+      {
+        name: 'Checkbox',
+        sort: 5,
+        cName: '复选按钮',
+        type: 'component',
+        show: true,
+        desc: '复选按钮',
+        author: 'Ymm0008'
+      },
+      {
+        name: 'Swiper',
+        sort: 6,
+        cName: '轮播',
+        type: 'component',
+        show: true,
+        desc: '轮播',
+        author: 'ailululu'
+      },
+      {
+        name: 'Avatar',
+        sort: 7,
+        cName: '头像',
+        type: 'component',
+        show: true,
+        desc: '头像',
+        author: 'ailululu'
+      },
+      {
+        name: 'Menu',
+        sort: 8,
+        cName: '菜单',
+        type: 'component',
+        show: true,
+        desc: '菜单',
+        author: 'vickyYE'
+      }
+    ]
+  },
+  {
+    name: '导航组件',
+    packages: [
+      {
+        name: 'Navbar',
+        sort: 3,
+        cName: '导航组件',
+        type: 'componment',
+        show: true,
+        desc: '导航组件',
+        author: 'liqiong43'
+      },
+      {
+        name: 'tab',
+        sort: 1,
+        cName: '标签组件',
+        type: 'component',
+        show: true,
+        desc: '标签组件',
+        author: 'zhenyulei'
+      }
+    ]
+  },
+  {
+    name: '数据录入',
+    packages: [
+      {
+        name: 'InputNumber',
+        sort: 1,
+        cName: '数字输入框',
+        type: 'component',
+        show: true,
+        desc: '数字输入框组件',
+        author: 'szg2008'
+      },
+      {
+        name: 'Rate',
+        sort: 2,
+        cName: '评分',
+        type: 'component',
+        show: true,
+        desc: '评分组件',
+        author: 'undo'
+      }
+    ]
+  },
+  {
+    name: '业务组件',
+    packages: []
+  }
+];

+ 15 - 0
src/packages/col/index.scss

@@ -0,0 +1,15 @@
+.nut-col {
+  float: left;
+  box-sizing: border-box;
+  word-break: break-all;
+}
+
+@for $i from 1 through 24 {
+  .nut-col-offset-#{$i} {
+    margin-left: 100/24 * $i * 1%;
+  }
+
+  .nut-col-#{$i} {
+    width: 100/24 * $i * 1%;
+  }
+}

+ 43 - 0
src/packages/col/index.vue

@@ -0,0 +1,43 @@
+<template>
+  <view class="nut-col" :class="classObject" :style="styleObj">
+    <slot></slot>
+  </view>
+</template>
+<script lang="ts">
+import { toRefs, watch, reactive, inject } from 'vue';
+import { createComponent } from '@/utils/create';
+const { componentName, create } = createComponent('col');
+
+export default create({
+  props: {
+    span: {
+      type: [String, Number],
+      default: '24'
+    },
+    offset: {
+      type: [String, Number],
+      default: '0'
+    }
+  },
+  setup(props, { emit, slots }) {
+    const gutter = inject('gutter');
+    const { offset, span } = toRefs(props);
+    const classObject = reactive({
+      ['nut-col-' + props.span]: true,
+      ['nut-col-offset-' + props.offset]: true
+    });
+    const styleObj = reactive({
+      'padding-left': gutter + 'px',
+      'padding-right': gutter + 'px'
+    });
+    return {
+      classObject,
+      styleObj
+    };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 4 - 4
src/packages/input/index.scss

@@ -22,12 +22,12 @@
   }
   .nut-text {
     flex: 1;
-    padding:0 10px;
-    .nut-text-limit{
-        float: right;
+    padding: 0 10px;
+    .nut-text-limit {
+      float: right;
     }
     .nut-text-core {
-        outline:none;
+      outline: none;
       display: block;
       box-sizing: border-box;
       width: 100%;

+ 332 - 0
src/packages/layout/demo.vue

@@ -0,0 +1,332 @@
+<template>
+  <div class="demo">
+    <h2>基础布局</h2>
+    <div class="box-item">
+      <nut-row>
+        <nut-col :span="12">
+          <div class="flex-content">span:12</div>
+        </nut-col>
+        <nut-col :span="12">
+          <div class="flex-content flex-content-light">span:12</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row>
+        <nut-col :span="8">
+          <div class="flex-content">span:8</div>
+        </nut-col>
+        <nut-col :span="8">
+          <div class="flex-content flex-content-light">span:8</div>
+        </nut-col>
+        <nut-col :span="8">
+          <div class="flex-content">span:8</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row>
+        <nut-col :span="6">
+          <div class="flex-content">span:6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">span:6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">span:6</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row>
+        <nut-col :span="4">
+          <div class="flex-content">span:4</div>
+        </nut-col>
+        <nut-col :span="4">
+          <div class="flex-content flex-content-light">span:4</div>
+        </nut-col>
+        <nut-col :span="4">
+          <div class="flex-content">span:4</div>
+        </nut-col>
+        <nut-col :span="4">
+          <div class="flex-content flex-content-light">span:4</div>
+        </nut-col>
+        <nut-col :span="4">
+          <div class="flex-content">span:4</div>
+        </nut-col>
+        <nut-col :span="4">
+          <div class="flex-content flex-content-light">span:4</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <h2>设置元素间距</h2>
+    <div class="box-item">
+      <nut-row :gutter="10">
+        <nut-col :span="6">
+          <div class="flex-content">span:6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">span:6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">span:6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">span:6</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <h2>Flex布局</h2>
+    <h2>wrap(是否换行)</h2>
+    <div class="box-item">
+      <nut-row type="flex" flexWrap="nowrap" :gutter="10">
+        <nut-col :span="6">
+          <div class="flex-content">1</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">2</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">3</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">4</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">5</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">7</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" flexWrap="wrap" :gutter="10">
+        <nut-col :span="6">
+          <div class="flex-content">1</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">2</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">3</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">4</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">5</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">7</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" flexWrap="reverse" :gutter="10">
+        <nut-col :span="6">
+          <div class="flex-content">1</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">2</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">3</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">4</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">5</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">7</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <h2>justify(主轴方向)</h2>
+    <div class="box-item">
+      <nut-row type="flex">
+        <nut-col :span="6">
+          <div class="flex-content">start</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">start</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">start</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" justify="center">
+        <nut-col :span="6">
+          <div class="flex-content">center</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">center</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">center</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" justify="end">
+        <nut-col :span="6">
+          <div class="flex-content">end</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">end</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">end</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" justify="space-between">
+        <nut-col :span="6">
+          <div class="flex-content">between</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">between</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">between</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" justify="space-around">
+        <nut-col :span="6">
+          <div class="flex-content">around</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">around</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">around</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <h2>align(侧轴方向)</h2>
+    <div class="box-item">
+      <nut-row type="flex" gutter="10" align="flex-start">
+        <nut-col :span="6">
+          <div class="flex-content flex-content-height">1</div>
+        </nut-col>
+        <nut-col :span="12">
+          <div class="flex-content flex-content-light"
+            >顶部对齐 - flex-start</div
+          >
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-height">3</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" gutter="10" align="center">
+        <nut-col :span="6">
+          <div class="flex-content flex-content-height">1</div>
+        </nut-col>
+        <nut-col :span="12">
+          <div class="flex-content flex-content-light">居中对齐 - center</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-height">3</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex" gutter="10" align="flex-end">
+        <nut-col :span="6">
+          <div class="flex-content flex-content-height">1</div>
+        </nut-col>
+        <nut-col :span="12">
+          <div class="flex-content flex-content-light">底部对齐 - flex-end</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-height">3</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <h2>分栏偏移</h2>
+    <div class="box-item">
+      <nut-row type="flex">
+        <nut-col :offset="6" span="6">
+          <div class="flex-content">offset:6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content flex-content-light">span:6</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">span:6</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex">
+        <nut-col span="6">
+          <div class="flex-content">span:6</div>
+        </nut-col>
+        <nut-col :offset="8" :span="6">
+          <div class="flex-content flex-content-light">offset:8</div>
+        </nut-col>
+        <nut-col :span="6">
+          <div class="flex-content">span:6</div>
+        </nut-col>
+      </nut-row>
+    </div>
+    <div class="box-item">
+      <nut-row type="flex">
+        <nut-col span="6" :offset="6">
+          <div class="flex-content">offset:6</div>
+        </nut-col>
+        <nut-col :span="6" :offset="6">
+          <div class="flex-content">offset:6</div>
+        </nut-col>
+      </nut-row>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { createComponent } from '@/utils/create';
+const { createDemo } = createComponent('layout');
+export default createDemo({});
+</script>
+
+<style lang="scss" scoped>
+.box-item {
+  background: #fff;
+  margin-bottom: 20px;
+  padding: 20px 20px 10px;
+  border: 1px solid #ddd;
+}
+.demo .nut-col {
+  margin-bottom: 10px;
+}
+.flex-content {
+  line-height: 30px;
+  color: #fff;
+  text-align: center;
+  background: #78a4f4;
+  &.flex-content-light {
+    background: #93b6f6;
+  }
+  &.flex-content-height {
+    height: 50px;
+  }
+}
+</style>

+ 331 - 0
src/packages/layout/doc.md

@@ -0,0 +1,331 @@
+# Layout 布局
+
+### 介绍
+
+用于快速进行布局
+
+### 安装
+
+``` javascript
+import { createApp } from 'vue';
+import { Row, Col } from '@nutui/nutui';
+
+const app = createApp();
+app.use(Row);
+app.use(Col);
+```
+
+## 代码演示
+
+### 基本用法
+
+```html
+<nut-row>
+    <nut-col :span="12">
+        <div class="flex-content">span:12</div>
+    </nut-col>
+    <nut-col :span="12">
+        <div class="flex-content flex-content-light">span:12</div>
+    </nut-col>
+</nut-row>
+<nut-row>
+    <nut-col :span="8">
+        <div class="flex-content">span:8</div>
+    </nut-col>
+    <nut-col :span="8">
+        <div class="flex-content flex-content-light">span:8</div>
+    </nut-col>
+    <nut-col :span="8">
+        <div class="flex-content">span:8</div>
+    </nut-col>
+</nut-row>
+<nut-row>
+    <nut-col :span="6">
+        <div class="flex-content">span:6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">span:6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">span:6</div>
+        </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">span:6</div>
+    </nut-col>
+</nut-row>
+<nut-row>
+    <nut-col :span="4">
+        <div class="flex-content">span:4</div>
+    </nut-col>
+    <nut-col :span="4">
+        <div class="flex-content flex-content-light">span:4</div>
+    </nut-col>
+    <nut-col :span="4">
+        <div class="flex-content">span:4</div>
+    </nut-col>
+    <nut-col :span="4">
+        <div class="flex-content flex-content-light">span:4</div>
+    </nut-col>
+    <nut-col :span="4">
+        <div class="flex-content">span:4</div>
+    </nut-col>
+    <nut-col :span="4">
+        <div class="flex-content flex-content-light">span:4</div>
+    </nut-col>
+</nut-row>
+
+```
+
+### 设置元素间距
+
+```html
+<nut-row :gutter="10">
+    <nut-col :span="6">
+        <div class="flex-content">span:6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">span:6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">span:6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">span:6</div>
+    </nut-col>
+</nut-row>
+            
+```
+
+### Flex布局
+
+#### wrap(是否换行)
+
+```html
+<nut-row type="flex" flexWrap="nowrap" :gutter="10">
+    <nut-col :span="6">
+        <div class="flex-content">1</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">2</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">3</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">4</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">5</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">7</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" flexWrap="wrap" :gutter="10">
+    <nut-col :span="6">
+        <div class="flex-content">1</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">2</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">3</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">4</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">5</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">7</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" flexWrap="reverse" :gutter="10">
+    <nut-col :span="6">
+        <div class="flex-content">1</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">2</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">3</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">4</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">5</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">7</div>
+    </nut-col>
+</nut-row>
+
+```
+
+#### justify(主轴方向)
+
+```html
+<nut-row type="flex">
+    <nut-col :span="6">
+        <div class="flex-content">start</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">start</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">start</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" justify="center">
+    <nut-col :span="6">
+        <div class="flex-content">center</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">center</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">center</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" justify="end">
+    <nut-col :span="6">
+        <div class="flex-content">end</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">end</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">end</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" justify="space-between">
+    <nut-col :span="6">
+        <div class="flex-content">between</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">between</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">between</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" justify="space-around">
+    <nut-col :span="6">
+        <div class="flex-content">around</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">around</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">around</div>
+    </nut-col>
+</nut-row>
+
+```
+
+#### align(侧轴方向)
+
+```html
+<nut-row type="flex" gutter="10" align="flex-start">
+    <nut-col :span="6">
+        <div class="flex-content flex-content-height">1</div>
+    </nut-col>
+    <nut-col :span="12">
+        <div class="flex-content flex-content-light">顶部对齐 - flex-start</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-height">3</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" gutter="10" align="center">
+    <nut-col :span="6">
+        <div class="flex-content flex-content-height">1</div>
+    </nut-col>
+    <nut-col :span="12">
+        <div class="flex-content flex-content-light">居中对齐 - center</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-height">3</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex" gutter="10" align="flex-end">
+    <nut-col :span="6">
+        <div class="flex-content flex-content-height">1</div>
+    </nut-col>
+    <nut-col :span="12">
+        <div class="flex-content flex-content-light">底部对齐 - flex-end</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-height">3</div>
+    </nut-col>
+</nut-row>
+
+```
+
+### 分栏偏移
+
+```html
+<nut-row type="flex">
+    <nut-col :offset="6" span="6">
+        <div class="flex-content">offset:6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content flex-content-light">span:6</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">span:6</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex">
+    <nut-col span="6">
+        <div class="flex-content">span:6</div>
+    </nut-col>
+    <nut-col :offset="8" :span="6">
+        <div class="flex-content flex-content-light">offset:8</div>
+    </nut-col>
+    <nut-col :span="6">
+        <div class="flex-content">span:6</div>
+    </nut-col>
+</nut-row>
+<nut-row type="flex">
+    <nut-col span="6" :offset="6">
+        <div class="flex-content">offset:6</div>
+    </nut-col>
+    <nut-col :span="6" :offset="6">
+        <div class="flex-content">offset:6</div>
+    </nut-col>
+</nut-row>
+
+```
+
+## Prop
+
+### row
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| type | 布局方式,可选值为flex | String | -
+| gutter | 列元素之间的间距(单位为px) | String/Number | -
+| tag | 自定义元素标签 | String | div
+| justify | Flex 主轴对齐方式,可选值为 start end center space-around space-between | String | start
+| align | Flex 交叉轴对齐方式,可选值为 flex-start center flex-end | String | flex-start
+| flex-wrap | Flex是否换行,可选值为 nowrap wrap reverse | String | nowrap
+
+### col
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| span | 列元素宽度(共分为24份,例如设置一行3个,那么span值为8) | String/Number | -
+| offset | 列元素偏移距离 | String/Number | - 
+

+ 81 - 0
src/packages/menu/demo.vue

@@ -0,0 +1,81 @@
+<template>
+  <div class="demo">
+    <h2>基础用法</h2>
+    <nut-menu>
+      <nut-menu-item
+        :menuList="menuList"
+        :title="title1"
+        @on-checked="getChecked"
+      ></nut-menu-item>
+      <nut-menu-item
+        :menuList="menuList2"
+        title="最新商品"
+        multiLine="2"
+      ></nut-menu-item>
+      <nut-menu-item
+        :menuList="menuList2"
+        title="筛选"
+        disabled
+      ></nut-menu-item>
+    </nut-menu>
+  </div>
+</template>
+
+<script lang="ts">
+import { ref, reactive, toRefs } from 'vue';
+import { createComponent } from '@/utils/create';
+const { createDemo } = createComponent('menu');
+export default createDemo({
+  props: {},
+  setup() {
+    const title1 = ref('标题1');
+    const resData = reactive({
+      menuList: [
+        {
+          value: '标签一'
+        },
+        {
+          value: '标签二标签二标签二标签二'
+        },
+        {
+          value: '标签三'
+        }
+      ],
+      menuList2: [
+        {
+          value: '标签1'
+        },
+        {
+          value: '标签2'
+        },
+        {
+          value: '标签3'
+        }
+      ]
+    });
+
+    const getChecked = (info: any) => {
+      console.log(11, info.value);
+    };
+    // function changeList() {
+    //   resData.editList.push({
+    //     title: '标签' + resData.editList.length
+    //   });
+    // }
+    // function switchTab(activeInddex: number, event: MouseEvent) {
+    //   console.log(activeInddex, event);
+    // }
+    return {
+      ...toRefs(resData),
+      title1
+      // changeList,
+      // switchTab
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.nut-menu {
+}
+</style>

+ 66 - 0
src/packages/menu/doc.md

@@ -0,0 +1,66 @@
+# Menu 菜单组件
+
+### 介绍
+
+基于 xxxxxxx
+
+### 安装
+
+``` javascript
+import { createApp } from 'vue';
+import { Menu } from '@nutui/nutui';
+
+const app = createApp();
+app.use(Menu);
+
+```
+
+## 代码演示
+
+### 基础用法1
+
+`Menu`  属性支持传入menu列表数据和title名称。
+
+```html
+<nut-menu>
+  <nut-menu-item :menuList="menuList" :title="title1"></nut-menu-item>
+  <nut-menu-item :menuList="menuList2" :title="title1"></nut-menu-item>
+</nut-menu>
+```
+
+### 基础用法2
+
+`Icon` 的 `name` 属性支持传入图标名称或图片链接。
+
+```html
+<nut-temp name="wifi"></nut-temp>
+<nut-temp name="mail"></nut-temp>
+```
+
+### 基础用法3
+
+`Icon` 的 `name` 属性支持传入图标名称或图片链接。
+
+```html
+<nut-temp name="wifi"></nut-temp>
+<nut-temp name="mail"></nut-temp>
+```
+
+
+## API
+
+### Props
+
+| 参数         | 说明                             | 类型   | 默认值           |
+|--------------|----------------------------------|--------|------------------|
+| name         | 图标名称或图片链接               | String | -                |
+| color        | 图标颜色                         | String | -                |
+| size         | 图标大小,如 `20px` `2em` `2rem` | String | -                |
+| class-prefix | 类名前缀,用于使用自定义图标     | String | `nutui-iconfont` |
+| tag          | HTML 标签                        | String | `i`              |
+
+### Events
+
+| 事件名 | 说明           | 回调参数     |
+|--------|----------------|--------------|
+| click  | 点击图标时触发 | event: Event |

+ 7 - 0
src/packages/menu/index.scss

@@ -0,0 +1,7 @@
+.nut-menu {
+  background: #fff;
+  display: flex;
+  align-items: center;
+  position: relative;
+  height: 46px;
+}

+ 45 - 0
src/packages/menu/index.vue

@@ -0,0 +1,45 @@
+<template>
+  <view class="nut-menu">
+    <slot></slot>
+  </view>
+</template>
+<script lang="ts">
+import { toRefs } from 'vue';
+import { createComponent } from '@/utils/create';
+import { useChildren } from '@/utils/useRelation/useChildren';
+export const MENU_KEY = 'nutMenu';
+const { componentName, create } = createComponent('menu');
+
+export default create({
+  props: {
+    disabled: {
+      //是否显示
+      type: Boolean,
+      default: false
+    },
+    type: {
+      //单选 simple  多选  multiple
+      type: String,
+      default: 'simple'
+    }
+  },
+  components: {},
+  emits: ['click'],
+
+  setup(props, { emit }) {
+    console.log('componentName', componentName);
+
+    // const { name, txt } = toRefs(props);
+
+    const handleClick = (event: Event) => {
+      emit('click', event);
+    };
+
+    // return { name, txt, handleClick };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 102 - 0
src/packages/menuitem/index.scss

@@ -0,0 +1,102 @@
+.nut-menu-item {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  padding: 0 5px;
+  &.disabled {
+    color: #999;
+  }
+  &.nut-menu-active {
+    .nut-menu-title {
+      font-weight: bold;
+      .icon {
+        background: url('https://img10.360buyimg.com/imagetools/jfs/t1/156044/7/582/372/5fd990b5Ea62c2694/551e7f58d421a9ae.png')
+          no-repeat;
+        transition: all ease 0.3s;
+        transform: rotate(-360deg);
+        background-size: contain;
+      }
+    }
+    .nut-menu-panel {
+      display: block;
+    }
+  }
+}
+.nut-menu-title {
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  .title-name {
+    white-space: nowrap;
+    max-width: 100px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+  .icon {
+    display: inline-block;
+    width: 6px;
+    height: 6px;
+    background: url('https://img13.360buyimg.com/imagetools/jfs/t1/152898/12/10149/452/5fd990b5Ec7c12d70/3bf06076b758bed1.png')
+      no-repeat;
+    background-size: contain;
+    transform: rotate(0deg);
+    transition: all ease 0.3s;
+    margin: 0 2px;
+  }
+}
+.nut-menu-panel {
+  display: none;
+  width: 100%;
+  position: absolute;
+  left: 0;
+  top: 46px;
+  color: #2d2d2d;
+  overflow: hidden;
+  background-color: #fff;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  -webkit-overflow-scrolling: touch;
+  z-index: 9998;
+  border-top: 1px solid #f7f8fa;
+  border-radius: 0 0 15px 15px;
+  box-shadow: 0 4px 5px 0px rgba(236, 236, 236, 0.25);
+  // &.active{
+  //   display: block;
+  // }
+}
+
+.menu-list {
+  display: flex;
+  padding: 10px 24px;
+  flex-direction: column;
+  &.bubble-line {
+    flex-flow: wrap;
+    .menu-option {
+      width: 50%;
+    }
+  }
+  &.three-line {
+    flex-flow: wrap;
+    .menu-option {
+      width: 32%;
+    }
+  }
+  .menu-option {
+    min-height: 24px;
+    line-height: 48px;
+    font-size: 14px;
+    color: #1a1a1a;
+    width: 100%;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+  .check-icon {
+    width: 14px;
+    height: 14px;
+    margin-right: 5px;
+    color: #fa2c19;
+  }
+}

+ 145 - 0
src/packages/menuitem/index.vue

@@ -0,0 +1,145 @@
+<template>
+  <view
+    class="nut-menu-item"
+    :class="[{ disabled: disabled }, { 'nut-menu-active': showPanel }]"
+  >
+    <view class="nut-menu-title" @click="handleMenuPanel">
+      <view class="title-name" v-html="menuTitle"></view>
+      <i class="icon" name="arrow-down"></i>
+    </view>
+    <view class="nut-menu-panel" ref="menuPanel">
+      <view
+        class="menu-list"
+        :class="[
+          { 'bubble-line': multiLine == 2 },
+          { 'three-line': multiLine == 3 }
+        ]"
+      >
+        <view
+          class="menu-option"
+          v-for="(item, index) in menuList"
+          :key="index"
+          @click="checkMenus(item, index)"
+          ><nut-icon
+            class="check-icon"
+            v-if="currMenu == index"
+            name="dongdong"
+            size="14px"
+          ></nut-icon
+          >{{ item.value }}</view
+        >
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts">
+import {
+  reactive,
+  toRefs,
+  onMounted,
+  ref,
+  nextTick,
+  computed,
+  watch,
+  onUnmounted
+} from 'vue';
+import { createComponent } from '@/utils/create';
+import { useParent } from '@/utils/useRelation/useParent';
+import { MENU_KEY } from './../menu/index.vue';
+import Icon from '@/packages/icon/index.vue';
+const { create } = createComponent('menu-item');
+
+export default create({
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    value: {
+      type: [String, Number],
+      default: ''
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    menuList: {
+      type: Array,
+      default: () => {
+        return [];
+      }
+    },
+    isVisible: {
+      //是否显示
+      type: Boolean,
+      default: false
+    },
+    multiLine: {
+      type: [String, Number],
+      default: 1 //可选值1、2、3
+    }
+  },
+  emits: ['on-checked'],
+  setup(props, { emit }) {
+    const { menuList, multiLine } = toRefs(props);
+    const menuTitle = ref(props.title);
+    const menu = useParent(MENU_KEY);
+    const parent: any = reactive(menu.parent as any);
+    const index: any = reactive(menu.index as any);
+    const state = reactive({
+      showPanel: false,
+      currMenu: 0
+      // menuTitle:''
+    });
+
+    const handleMenuPanel = () => {
+      //禁用
+      if (props.disabled) return;
+      state.showPanel = !state.showPanel;
+    };
+    //menu列表浮层展示和隐藏
+    const handleShowAndHide = (event: any) => {
+      const menuBox = document.querySelectorAll('.nut-menu-active')[0];
+      if (menuBox && state.showPanel) {
+        if (!menuBox.contains(event.target)) {
+          state.showPanel = false;
+        }
+      }
+    };
+    const checkMenus = (item: any, index: number) => {
+      console.log(item);
+      menuTitle.value = item.value;
+      state.currMenu = index;
+      emit('on-checked', menuTitle.value);
+    };
+    onMounted(() => {
+      document.addEventListener(
+        'mouseup',
+        (event: any) => {
+          handleShowAndHide(event);
+        },
+        false
+      );
+    });
+
+    onUnmounted(() => {
+      document.removeEventListener('mouseup', (event: any) => {
+        handleShowAndHide(event);
+      }),
+        false;
+    });
+    return {
+      ...toRefs(state),
+      ...toRefs(parent),
+      handleMenuPanel,
+      checkMenus,
+      menuTitle,
+      multiLine
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+@import './index.scss';
+</style>

+ 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>

+ 49 - 0
src/packages/row/index.scss

@@ -0,0 +1,49 @@
+.nut-row {
+  &:after {
+    display: block;
+    height: 0;
+    clear: both;
+    visibility: hidden;
+    content: '';
+  }
+}
+.nut-row-flex {
+  display: flex;
+  &:after {
+    display: none;
+  }
+  .nut-col {
+    float: none;
+  }
+}
+.nut-row-justify-center {
+  justify-content: center;
+}
+.nut-row-justify-end {
+  justify-content: flex-end;
+}
+.nut-row-justify-space-between {
+  justify-content: space-between;
+  align-items: center;
+}
+.nut-row-justify-space-around {
+  justify-content: space-around;
+}
+.nut-row-align-flex-start {
+  align-items: flex-start;
+}
+.nut-row-align-center {
+  align-items: center;
+}
+.nut-row-align-flex-end {
+  align-items: flex-end;
+}
+.nut-row-flex-wrap {
+  flex-wrap: wrap;
+}
+.nut-row-flex-nowrap {
+  flex-wrap: nowrap;
+}
+.nut-row-flex-reverse {
+  flex-wrap: wrap-reverse;
+}

+ 64 - 0
src/packages/row/index.vue

@@ -0,0 +1,64 @@
+<template>
+  <view class="nut-row" :class="getClassObject()">
+    <slot></slot>
+  </view>
+</template>
+<script lang="ts">
+import { computed, provide } from 'vue';
+import { createComponent } from '@/utils/create';
+const { componentName, create } = createComponent('row');
+
+export default create({
+  props: {
+    type: {
+      type: String,
+      default: ''
+    },
+    gutter: {
+      type: [String, Number],
+      default: ''
+    },
+    tag: {
+      type: String,
+      default: 'div'
+    },
+    justify: {
+      type: String,
+      default: 'start'
+    },
+    align: {
+      type: String,
+      default: 'flex-start'
+    },
+    flexWrap: {
+      type: String,
+      default: 'nowrap'
+    }
+  },
+  setup(props, { slots }) {
+    provide('gutter', props.gutter);
+    const getClass = (prefix, type) => {
+      return prefix
+        ? type
+          ? `nut-row-${prefix}-${type}`
+          : ''
+        : `nut-row-${type}`;
+    };
+    const getClassObject = () => {
+      return `
+              ${getClass('', props.type)}
+              ${getClass('justify', props.justify)}
+              ${getClass('align', props.align)}
+              ${getClass('flex', props.flexWrap)}
+              `;
+    };
+
+    return {
+      getClassObject
+    };
+  }
+});
+</script>
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 16 - 4
src/sites/doc/views/Main.vue

@@ -17,7 +17,11 @@
 </template>
 <script lang="ts">
 import { defineComponent, onMounted, reactive } from 'vue';
-import { onBeforeRouteUpdate, RouteLocationNormalized, useRoute } from 'vue-router';
+import {
+  onBeforeRouteUpdate,
+  RouteLocationNormalized,
+  useRoute
+} from 'vue-router';
 import { currentRoute } from '@/sites/assets/util/ref';
 import Header from '@/sites/doc/components/Header.vue';
 export default defineComponent({
@@ -56,7 +60,8 @@ export default defineComponent({
       margin-top: 10px;
       width: 69px;
       height: 27px;
-      background: url(https://storage.360buyimg.com/imgtools/09516173b9-9b32b9d0-3864-11eb-9a56-0104487ad2b0.png) no-repeat;
+      background: url(https://storage.360buyimg.com/imgtools/09516173b9-9b32b9d0-3864-11eb-9a56-0104487ad2b0.png)
+        no-repeat;
       background-size: cover;
     }
     .content-subTitle {
@@ -73,7 +78,13 @@ export default defineComponent({
         color: rgba(255, 255, 255, 1);
         width: 170px;
         height: 50px;
-        background: linear-gradient(135deg, rgba(250, 25, 44, 1) 0%, rgba(250, 39, 40, 1) 45%, rgba(250, 56, 31, 1) 83%, rgba(250, 63, 25, 1) 100%);
+        background: linear-gradient(
+          135deg,
+          rgba(250, 25, 44, 1) 0%,
+          rgba(250, 39, 40, 1) 45%,
+          rgba(250, 56, 31, 1) 83%,
+          rgba(250, 63, 25, 1) 100%
+        );
         border-radius: 29px;
       }
       .rightButton {
@@ -94,7 +105,8 @@ export default defineComponent({
     .content-img {
       width: 900px;
       height: 514px;
-      background: url(https://storage.360buyimg.com/imgtools/732c3242e9-9b1946b0-391a-11eb-8a8d-55c57d054ae1.png) no-repeat;
+      background: url(https://storage.360buyimg.com/imgtools/732c3242e9-9b1946b0-391a-11eb-8a8d-55c57d054ae1.png)
+        no-repeat;
       background-size: cover;
     }
   }