Browse Source

feat: 菜单组件提交

yewenwen 5 years ago
parent
commit
a65cb0fb96

+ 9 - 0
src/config.js

@@ -237,6 +237,15 @@ module.exports = {
           show: true,
           desc: '标签组件',
           author: 'zhenyulei'
+        },
+        {
+          name: 'menu',
+          sort: 2,
+          cName: '菜单组件',
+          type: 'component',
+          show: true,
+          desc: '下拉菜单组件',
+          author: 'vickyYE'
         }
       ]
     },

+ 107 - 37
src/packages/menu/demo.vue

@@ -2,15 +2,42 @@
   <div class="demo">
     <h2>基础用法</h2>
     <nut-menu>
+      <nut-menu-item :menuList="menuList" title="最新商品"></nut-menu-item>
+      <nut-menu-item :menuList="menuList" :title="title"></nut-menu-item>
+    </nut-menu>
+
+    <h2>多列展示</h2>
+    <nut-menu>
       <nut-menu-item
-        :menuList="menuList"
-        :title="title1"
-        @on-checked="getChecked"
+        class="base-style"
+        :menuList="menuList2"
+        title="单列展示"
+        multiStyle="1"
+        maxHeight="200"
       ></nut-menu-item>
       <nut-menu-item
         :menuList="menuList2"
-        title="最新商品"
-        multiLine="2"
+        title="双列展示"
+        multiStyle="2"
+      ></nut-menu-item>
+      <nut-menu-item
+        :menuList="menuList2"
+        title="三列展示"
+        multiStyle="3"
+      ></nut-menu-item>
+    </nut-menu>
+
+    <h2>禁用操作</h2>
+    <p class="tips"
+      >`disabled` 属性可对菜单列表进行禁用操作。`autoClose`
+      属性控制下拉菜单列表是否选择后自动收起,默认自动收起。</p
+    >
+    <nut-menu>
+      <nut-menu-item :menuList="menuList" title="最新商品"></nut-menu-item>
+      <nut-menu-item
+        :menuList="menuList"
+        title="禁止自动收起"
+        :autoClose="false"
       ></nut-menu-item>
       <nut-menu-item
         :menuList="menuList2"
@@ -18,6 +45,38 @@
         disabled
       ></nut-menu-item>
     </nut-menu>
+
+    <h2>点击事件</h2>
+    <p class="tips"
+      >标题点击事件`menu-click`,菜单列表选择点击事件`on-change`</p
+    >
+    <nut-menu>
+      <nut-menu-item
+        :menuList="menuList"
+        title="选择菜单列表项"
+        multiStyle="2"
+        @menu-click="alertText($event, 'title')"
+        @on-change="getChecked"
+      ></nut-menu-item>
+      <nut-menu-item
+        :menuList="menuList2"
+        title="选中标题触发"
+        disabled
+        @menu-click="alertText"
+      ></nut-menu-item>
+    </nut-menu>
+
+    <h2>自定义内容</h2>
+    <nut-menu>
+      <nut-menu-item title="自定义选项">
+        <div class="user-style">
+          <nut-cell title="我是标题" desc="描述文字"> </nut-cell>
+          <nut-cell>
+            <nut-button size="large" type="primary">确认提交</nut-button>
+          </nut-cell>
+        </div>
+      </nut-menu-item>
+    </nut-menu>
   </div>
 </template>
 
@@ -28,54 +87,65 @@ const { createDemo } = createComponent('menu');
 export default createDemo({
   props: {},
   setup() {
-    const title1 = ref('标题1');
+    // const title1 = ref('热门推荐');
     const resData = reactive({
+      title: '热门推荐',
       menuList: [
-        {
-          value: '标签一'
-        },
-        {
-          value: '标签二标签二标签二标签二'
-        },
-        {
-          value: '标签三'
-        }
+        { value: '手机' },
+        { value: '电脑' },
+        { value: '家用电器' },
+        { value: '日用百货' }
       ],
       menuList2: [
-        {
-          value: '标签1'
-        },
-        {
-          value: '标签2'
-        },
-        {
-          value: '标签3'
-        }
+        { value: '热门推荐', id: 111 },
+        { value: '手机数码', id: 112 },
+        { value: '电脑办公', id: 113 },
+        { value: '美妆护肤', id: 114 },
+        { value: '个护清洁', id: 115 },
+        { value: '汽车生活', id: 116 },
+        { value: '京东超市', id: 117 },
+        { value: '母婴童装', id: 118 }
       ]
     });
 
-    const getChecked = (info: any) => {
-      console.log(11, info.value);
+    const getChecked = (info: any, name: string) => {
+      alert('选择菜单选项:' + name);
+      console.log(11, info, name);
     };
-    // function changeList() {
-    //   resData.editList.push({
-    //     title: '标签' + resData.editList.length
-    //   });
-    // }
-    // function switchTab(activeInddex: number, event: MouseEvent) {
-    //   console.log(activeInddex, event);
-    // }
+    const alertText = (info, type) => {
+      console.log(info, type);
+      if (type == 'title') {
+        alert('菜单标题点击:' + info);
+      } else {
+        alert('禁用操作');
+      }
+    };
+
     return {
       ...toRefs(resData),
-      title1
-      // changeList,
-      // switchTab
+      getChecked,
+      alertText
     };
   }
 });
 </script>
 
 <style lang="scss" scoped>
+.tips {
+  font-size: 12px;
+  color: #909ca4;
+  margin-top: -10px;
+  margin-bottom: 10px;
+}
 .nut-menu {
 }
+.base-style.nut-menu-item {
+  .nut-menu-panel {
+    max-height: 300px !important;
+    overflow: auto;
+  }
+}
+.user-style {
+  padding: 20px;
+}
 </style>

+ 94 - 18
src/packages/menu/doc.md

@@ -2,7 +2,7 @@
 
 ### 介绍
 
-基于 xxxxxxx
+下拉选择菜单组件
 
 ### 安装
 
@@ -19,33 +19,107 @@ app.use(Menu);
 
 ### 基础用法1
 
-`Menu`  属性支持传入menu列表数据和title名称。
+`Menu`  属性支持传入列表数据menuList和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-item :menuList="menuList" title="最新商品" ></nut-menu-item>
+  <nut-menu-item :menuList="menuList" :title="title" ></nut-menu-item>
 </nut-menu>
 ```
+```js
+ setup() {
+    const resData = reactive({
+      title: '热门推荐',
+      menuList: [
+        {value: '手机'},
+        {value: '电脑'},
+        {value: '家用电器'},
+        {value: '日用百货'}
+      ]
+    });
+ }
 
-### 基础用法2
+```
+
+### 菜单多列展示
 
-`Icon` 的 `name` 属性支持传入图标名称或图片链接。
+`Menu` 的 ` multiStyle` 属性配置1列、2列、3列展示菜单列表,默认单列展示。
+`maxHeight` 属性可控制菜单列表的最大高度。
 
 ```html
-<nut-temp name="wifi"></nut-temp>
-<nut-temp name="mail"></nut-temp>
+<nut-menu>
+    <nut-menu-item :menuList="menuList2" title="单列展示" multiStyle="1" maxHeight="200"></nut-menu-item>
+    <nut-menu-item :menuList="menuList2" title="双列展示"  multiStyle="2"></nut-menu-item>
+    <nut-menu-item :menuList="menuList2" title="三列展示"  multiStyle="3"></nut-menu-item>
+</nut-menu>
 ```
 
-### 基础用法3
+### 禁用操作
+
+`Menu` 的 `disabled` 属性可对菜单列表进行禁用操作。
+`autoClose` 属性控制下拉菜单列表是否选择后自动收起,默认自动收起。
+
+```html
+<nut-menu>
+    <nut-menu-item :menuList="menuList" title="最新商品"></nut-menu-item>
+    <nut-menu-item :menuList="menuList" :title="title" :autoClose="false"></nut-menu-item>
+    <nut-menu-item :menuList="menuList2" title="筛选" disabled ></nut-menu-item>
+</nut-menu>
+```
+### 点击事件
 
-`Icon` 的 `name` 属性支持传入图标名称或图片链接。
+`Menu` 的 `@menu-click` 事件返回点击的菜单标题,`@on-change`事件返回菜单列表选中的数据
 
 ```html
-<nut-temp name="wifi"></nut-temp>
-<nut-temp name="mail"></nut-temp>
+<nut-menu>
+    <nut-menu-item
+        :menuList="menuList2"
+        title="选择菜单列表项"
+        multiStyle="2"
+        @menu-click="alertText($event, 'title')"
+        @on-change="getChecked"
+    ></nut-menu-item>
+    <nut-menu-item
+        :menuList="menuList2"
+        title="选中标题触发"
+        disabled
+        @menu-click="alertText"
+    ></nut-menu-item>
+ </nut-menu>
+```
+```js
+const getChecked = (info: any, name: string) => {
+    alert('选择菜单选项:' + name);
+    console.log(11, info, name);
+};
+const alertText = (info, type) => {
+    console.log(info, type);
+    if (type == 'title') {
+        alert('菜单标题点击:' + info);
+    } else {
+        alert('禁用操作');
+    }
+};
 ```
 
+### 自定义内容
+
+
+```html
+<nut-menu>
+    <nut-menu-item title="自定义选项">
+        <div class="user-style">
+          <nut-cell>
+            设置为默认 <nut-switch></nut-switch>
+          </nut-cell>
+          <nut-cell>
+            <nut-button size="large" type="primary">确认提交</nut-button>
+          </nut-cell>
+        </div>
+    </nut-menu-item>
+</nut-menu>
+```
 
 ## API
 
@@ -53,14 +127,16 @@ app.use(Menu);
 
 | 参数         | 说明                             | 类型   | 默认值           |
 |--------------|----------------------------------|--------|------------------|
-| name         | 图标名称或图片链接               | String | -                |
-| color        | 图标颜色                         | String | -                |
-| size         | 图标大小,如 `20px` `2em` `2rem` | String | -                |
-| class-prefix | 类名前缀,用于使用自定义图标     | String | `nutui-iconfont` |
-| tag          | HTML 标签                        | String | `i`              |
+| title         | 菜单标题名称或可为菜单列表第一项,必填     | String | -                |
+| menuList        | 菜单列表数据,必填                     | Array | -                |
+| multiStyle        | 列表列数设置,默认1列,可选值 `1` `2` `3` | String, Number | 1                |
+| disabled | 是否开启禁用设置,默认不开启    | Boolean | false |
+| maxHeight | 菜单列表最大高度,单位px    | String, Number | - |
+| autoClose | 选择后下拉菜单列表是否自动收起,默认自动收起   | Boolean | true |
 
 ### Events
 
 | 事件名 | 说明           | 回调参数     |
 |--------|----------------|--------------|
-| click  | 点击图标时触发 | event: Event |
+| menu-click  | 点击菜单标题触发,返回菜单标题名称 | event: Event |
+| on-change  | 点击菜单列表选项触发,返回选中菜单项数据、名称 | event: Event |

+ 6 - 16
src/packages/menu/index.vue

@@ -12,30 +12,20 @@ const { componentName, create } = createComponent('menu');
 
 export default create({
   props: {
-    disabled: {
-      //是否显示
-      type: Boolean,
-      default: false
-    },
     type: {
-      //单选 simple  多选  multiple
+      //单选 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 };
+    // const { autoClose } = toRefs(props);
+    // const handleClick = (event: Event) => {
+    //   emit('click', event);
+    // };
+    // return { autoClose };
   }
 });
 </script>

+ 12 - 10
src/packages/menuitem/index.scss

@@ -12,11 +12,9 @@
     .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;
+        color: #1a1a1a;
         transition: all ease 0.3s;
-        transform: rotate(-360deg);
-        background-size: contain;
+        transform: rotate(-180deg);
       }
     }
     .nut-menu-panel {
@@ -38,12 +36,11 @@
     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;
+    color: #909ca4;
     transform: rotate(0deg);
     transition: all ease 0.3s;
     margin: 0 2px;
+    transform-origin: right;
   }
 }
 .nut-menu-panel {
@@ -62,6 +59,7 @@
   border-top: 1px solid #f7f8fa;
   border-radius: 0 0 15px 15px;
   box-shadow: 0 4px 5px 0px rgba(236, 236, 236, 0.25);
+  overflow: auto;
   // &.active{
   //   display: block;
   // }
@@ -69,7 +67,7 @@
 
 .menu-list {
   display: flex;
-  padding: 10px 24px;
+  padding: 10px 15px;
   flex-direction: column;
   &.bubble-line {
     flex-flow: wrap;
@@ -80,18 +78,22 @@
   &.three-line {
     flex-flow: wrap;
     .menu-option {
-      width: 32%;
+      width: 33%;
     }
   }
   .menu-option {
     min-height: 24px;
-    line-height: 48px;
+    line-height: 42px;
     font-size: 14px;
     color: #1a1a1a;
     width: 100%;
     white-space: nowrap;
     overflow: hidden;
     text-overflow: ellipsis;
+    padding: 0 5px;
+    &.checked {
+      font-weight: bold;
+    }
   }
   .check-icon {
     width: 14px;

+ 30 - 23
src/packages/menuitem/index.vue

@@ -5,30 +5,37 @@
   >
     <view class="nut-menu-title" @click="handleMenuPanel">
       <view class="title-name" v-html="menuTitle"></view>
-      <i class="icon" name="arrow-down"></i>
+      <nut-icon class="icon" name="arrow-down" size="6px"></nut-icon>
     </view>
-    <view class="nut-menu-panel" ref="menuPanel">
+    <view
+      class="nut-menu-panel"
+      ref="menuPanel"
+      :style="`max-height:${maxHeight}px`"
+    >
       <view
+        v-if="menuList && menuList.length"
         class="menu-list"
         :class="[
-          { 'bubble-line': multiLine == 2 },
-          { 'three-line': multiLine == 3 }
+          { 'bubble-line': multiStyle == 2 },
+          { 'three-line': multiStyle == 3 }
         ]"
       >
         <view
           class="menu-option"
+          :class="{ checked: currMenu == index }"
           v-for="(item, index) in menuList"
           :key="index"
           @click="checkMenus(item, index)"
           ><nut-icon
             class="check-icon"
             v-if="currMenu == index"
-            name="dongdong"
+            name="Check"
             size="14px"
           ></nut-icon
           >{{ item.value }}</view
         >
       </view>
+      <slot></slot>
     </view>
   </view>
 </template>
@@ -55,10 +62,6 @@ export default create({
       type: String,
       default: ''
     },
-    value: {
-      type: [String, Number],
-      default: ''
-    },
     disabled: {
       type: Boolean,
       default: false
@@ -69,32 +72,35 @@ export default create({
         return [];
       }
     },
-    isVisible: {
-      //是否显示
+    autoClose: {
       type: Boolean,
-      default: false
+      default: true
     },
-    multiLine: {
+    multiStyle: {
       type: [String, Number],
       default: 1 //可选值1、2、3
+    },
+    maxHeight: {
+      type: [String, Number],
+      default: ''
     }
   },
-  emits: ['on-checked'],
+  emits: ['on-change', 'menu-click'],
   setup(props, { emit }) {
-    const { menuList, multiLine } = toRefs(props);
+    const { menuList, multiStyle } = 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 = () => {
+      emit('menu-click', menuTitle.value);
       //禁用
-      if (props.disabled) return;
+      if (props.disabled) {
+        return;
+      }
       state.showPanel = !state.showPanel;
     };
     //menu列表浮层展示和隐藏
@@ -107,10 +113,12 @@ export default create({
       }
     };
     const checkMenus = (item: any, index: number) => {
-      console.log(item);
       menuTitle.value = item.value;
       state.currMenu = index;
-      emit('on-checked', menuTitle.value);
+      if (props.autoClose) {
+        state.showPanel = false;
+      }
+      emit('on-change', item, menuTitle.value);
     };
     onMounted(() => {
       document.addEventListener(
@@ -130,11 +138,10 @@ export default create({
     });
     return {
       ...toRefs(state),
-      ...toRefs(parent),
       handleMenuPanel,
       checkMenus,
       menuTitle,
-      multiLine
+      multiStyle
     };
   }
 });