Browse Source

feat: actionsheet

Drjingfubo 4 years ago
parent
commit
6bf8ef9e65

+ 10 - 0
src/config.json

@@ -340,6 +340,16 @@
           "sort": 16,
           "show": true,
           "author": "yangxiaolu3"
+        },
+        {
+          "version": "3.0.0",
+          "name": "Drag",
+          "type": "component",
+          "cName": "拖拽",
+          "desc": "拖拽组件",
+          "sort": 16,
+          "show": false,
+          "author": "Drjingfubo"
         }
       ]
     },

+ 1 - 0
src/packages/ShortPassword/index.scss

@@ -17,6 +17,7 @@
 
   .nut-input-real {
     padding: 0 12px;
+    opacity: 0;
   }
 }
 

+ 1 - 1
src/packages/ShortPassword/index.vue

@@ -126,6 +126,6 @@ export default create({
 });
 </script>
 
-<style lang="scss">
+<style scoped lang="scss">
 @import 'index.scss';
 </style>

+ 72 - 61
src/packages/actionsheet/demo.vue

@@ -2,71 +2,75 @@
   <div class="demo-list demo">
     <h4>基本用法(选择类)</h4>
     <div>
-      <nut-cell
-        :showIcon="true"
-        :isLink="true"
-        @click="switchActionSheet('isVisible1')"
-      >
-        <span><label>基础用法</label></span>
-        <div class="selected-option">{{ state.val1 }}</div>
-      </nut-cell>
-      <nut-cell
-        :showIcon="true"
-        :isLink="true"
-        @click="switchActionSheet('isVisible2')"
-      >
-        <span><label>展示取消按钮</label></span>
-        <div class="selected-option">{{ state.val2 }}</div>
-      </nut-cell>
       <div>
-        <nut-cell :isLink="true" @click="switchActionSheet('isVisible3')">
-          <span><label>展示描述信息</label></span>
+        <nut-cell
+          :showIcon="true"
+          :isLink="true"
+          @click="switchActionSheet('isVisible1')"
+        >
+          <span><label>基础用法</label></span>
+          <div class="selected-option">{{ state.val1 }}</div>
         </nut-cell>
-      </div>
-      <h4>选项状态</h4>
+        <nut-cell
+          :showIcon="true"
+          :isLink="true"
+          @click="switchActionSheet('isVisible2')"
+        >
+          <span><label>展示取消按钮</label></span>
+          <div class="selected-option">{{ state.val2 }}</div>
+        </nut-cell>
+        <div>
+          <nut-cell :isLink="true" @click="switchActionSheet('isVisible3')">
+            <span><label>展示描述信息</label></span>
+            <div class="selected-option">{{ state.val3 }}</div>
+          </nut-cell>
+        </div>
+        <h4>选项状态</h4>
 
-      <nut-cell :isLink="true" @click="switchActionSheet('isVisible4')">
-        <span><label>选项状态</label></span>
-        <!-- <div class="selected-option">打开</div> -->
-      </nut-cell>
-      <h4>自定义面板</h4>
+        <nut-cell :isLink="true" @click="switchActionSheet('isVisible4')">
+          <span><label>选项状态</label></span>
+          <!-- <div class="selected-option">打开</div> -->
+        </nut-cell>
+        <h4>自定义面板</h4>
 
-      <nut-cell :isLink="true" @click="switchActionSheet('isVisible5')">
-        <span><label>自定义内容</label></span>
-        <!-- <div class="selected-option">打开</div> -->
-      </nut-cell>
+        <nut-cell :isLink="true" @click="switchActionSheet('isVisible5')">
+          <span><label>自定义内容</label></span>
+          <!-- <div class="selected-option">打开</div> -->
+        </nut-cell>
+      </div>
+      <!-- demo 基础用法 -->
+      <nut-actionsheet
+        :is-visible="state.isVisible1"
+        :menu-items="menuItemsOne"
+        @choose="chooseItem"
+      ></nut-actionsheet>
+      <!-- demo(带取消按钮) -->
+      <nut-actionsheet
+        :is-visible="state.isVisible2"
+        cancelTxt="取消"
+        :menu-items="menuItemsOne"
+        @choose="chooseItemTwo"
+      ></nut-actionsheet>
+      <!-- 展示描述信息 -->
+      <nut-actionsheet
+        :is-visible="state.isVisible3"
+        :description="state.desc"
+        :menu-items="menuItemsTwo"
+        @choose="chooseItemThree"
+        cancelTxt="取消"
+      >
+      </nut-actionsheet>
+      <!-- demo 选项状态-->
+      <nut-actionsheet
+        :is-visible="state.isVisible4"
+        cancelTxt="取消"
+        :menu-items="menuItemsThree"
+      ></nut-actionsheet>
+      <!-- demo 自定义 -->
+      <nut-actionsheet :is-visible="state.isVisible5" title="标题">
+        <div class="myContent">内容</div>
+      </nut-actionsheet>
     </div>
-    <!-- demo 基础用法 -->
-    <nut-actionsheet
-      :is-visible="state.isVisible1"
-      :menu-items="menuItemsOne"
-      @choose="chooseItem"
-    ></nut-actionsheet>
-    <!-- demo(带取消按钮) -->
-    <nut-actionsheet
-      :is-visible="state.isVisible2"
-      cancelTxt="取消"
-      :menu-items="menuItemsOne"
-      @choose="chooseItemTwo"
-    ></nut-actionsheet>
-
-    <nut-actionsheet
-      :is-visible="state.isVisible3"
-      :description="state.desc"
-      :menu-items="menuItemsTwo"
-      cancelTxt="取消"
-    >
-    </nut-actionsheet>
-    <!-- demo 选项状态-->
-    <nut-actionsheet
-      :is-visible="state.isVisible4"
-      cancelTxt="取消"
-      :menu-items="menuItemsThree"
-    ></nut-actionsheet>
-    <!-- demo 自定义 -->
-    <nut-actionsheet :is-visible="state.isVisible5" cancelTxt="取消">
-      <div class="custom-wrap"><span>自定义</span></div>
-    </nut-actionsheet>
   </div>
 </template>
 
@@ -130,7 +134,7 @@ export default createDemo({
       }
     ];
     const switchActionSheet = param => {
-      state[`${param}`] = !state[`${param}`];
+      state[param] = !state[param];
       //   console.log(state[`${param}`], '2');
     };
 
@@ -142,6 +146,9 @@ export default createDemo({
     function chooseItemTwo(itemParams) {
       state.val2 = itemParams.name;
     }
+    function chooseItemThree(itemParams) {
+      state.val3 = itemParams.name;
+    }
 
     return {
       state,
@@ -150,6 +157,7 @@ export default createDemo({
       menuItemsThree,
       chooseItem,
       chooseItemTwo,
+      chooseItemThree,
       switchActionSheet
     };
   }
@@ -178,4 +186,7 @@ export default createDemo({
 .nut-cell {
   justify-content: space-between;
 }
+.myContent {
+  padding: 10px 10px 160px;
+}
 </style>

+ 63 - 201
src/packages/actionsheet/doc.md

@@ -6,51 +6,22 @@
 
 默认
 ```html
-<div @click.native="switchActionSheet">
-    <span class="title"><label>性别</label></span>
-    <span class="selected-option">{{sex}}</span>
+<div @click="switchActionSheet">
+   <span><label>基础用法</label></span>
+   <div class="selected-option">state.val }}</div>
 </div>
-<nut-actionsheet :is-visible="isVisible" 
-    @close="switchActionSheet"
-    :menu-items="menuItems"
-    @choose="chooseItem"
-></nut-actionsheet>
-```
-```javascript
-export default {
-    data() {
-        return {
-            sex: '请选择',
-            isVisible: false,
-            menuItems: [
-                {
-                    'name': '男',
-                    'value': 0
-                },
-                {
-                    'name': '女',
-                    'value': 1
-                }
-            ]
-        };
-    },
-    methods: {
-        switchActionSheet() {
-            this.isVisible = !this.isVisible;
-        },
-
-        chooseItem(itemParams) {
-            this.sex = itemParams.name;
-        }
-    }
-};
+<nut-actionsheet
+        :is-visible="state.isVisible"
+        :menu-items="menuItems"
+        @choose="chooseItem"
+      ></nut-actionsheet>
 ```
 
-取消按钮
+## 展示取消按钮
 ```html
-<div @click.native="switchActionSheet">
-    <span class="title"><label>性别</label></span>
-    <span class="selected-option">{{sex}}</span>
+<div @click="switchActionSheet">
+   <span><label>展示取消按钮</label></span>
+    <div class="selected-option">state.val }}</div>
 </div>
  <nut-actionsheet :is-visible="isVisible" 
     @close="switchActionSheet"
@@ -59,165 +30,36 @@ export default {
     cancelTxt="取消"
 ></nut-actionsheet>
 ```
-```javascript
-export default {
-    data() {
-        return {
-            sex: '请选择',
-            isVisible: false,
-            menuItems: [
-                {
-                    'name': '男',
-                    'value': 0
-                },
-                {
-                    'name': '女',
-                    'value': 1
-                }
-            ]
-        };
-    },
-    methods: {
-        switchActionSheet() {
-            this.isVisible = !this.isVisible;
-        },
-
-        chooseItem(itemParams) {
-            this.sex = itemParams.name;
-        }
-    }
-};
-```
-
-高亮已选项
+## 展示描述信息
 ```html
 <div @click.native="switchActionSheet">
-    <span class="title"><label>性别</label></span>
-    <span class="selected-option">{{sex}}</span>
+   <span><label>展示取消按钮</label></span>
+    <div class="selected-option">state.val }}</div>
 </div>
-<nut-actionsheet :is-visible="isVisible" 
+ <nut-actionsheet :is-visible="isVisible" 
     @close="switchActionSheet"
+    description="state.desc"
     :menu-items="menuItems"
     @choose="chooseItem"
-    :chooseTagValue="sex"
+    cancelTxt="取消"
 ></nut-actionsheet>
 ```
-```javascript
-export default {
-    data() {
-        return {
-            sex: '请选择',
-            isVisible: false,
-            menuItems: [
-                {
-                    'name': '男',
-                    'value': 0
-                },
-                {
-                    'name': '女',
-                    'value': 1
-                }
-            ]
-        };
-    },
-    methods: {
-        switchActionSheet() {
-            this.isVisible = !this.isVisible;
-        },
-
-        chooseItem(itemParams) {
-            this.sex = itemParams.name;
-        }
-    }
-};
-```
 
-设置禁用状态
+## 选项状态
 ```html
 <div @click.native="switchActionSheet">
     <span class="title"><label>性别</label></span>
     <span class="selected-option">{{sex}}</span>
 </div>
-<nut-actionsheet :is-visible="isVisible" 
-    @close="switchActionSheet"
-    :menu-items="menuItems"
-    @choose="chooseItem"
-    :chooseTagValue="sex"
-></nut-actionsheet>
-```
-```javascript
-export default {
-    data() {
-        return {
-            sex: '请选择',
-            isVisible: false,
-            menuItems: [
-                {
-                    'name': '男',
-                    'value': 0,
-                    'disable': false
-                },
-                {
-                    'name': '女',
-                    'value': 1,
-                    'disable': true
-                }
-            ]
-        };
-    },
-    methods: {
-        switchActionSheet() {
-            this.isVisible = !this.isVisible;
-        },
-
-        chooseItem(itemParams) {
-            this.sex = itemParams.name;
-        }
-    }
-};
-```
-
-## 提示
-```html
-<div @click.native="switchActionSheet">
-    <span class="title"><label>我就列表测试数据</label></span>
-    <span class="sub-title">我是描述~~~~</span>
-    <div class="selected-option">删除本条</div>
-</div>
-<nut-actionsheet :is-visible="isVisible" 
-    :menu-items="menuItems4" 
-    chooseTagValue="确定"
-    cancelTxt="取消"
-    @close="switchActionSheet"
-    @choose="choose"
->
-    <span slot="title"><label>确定删除吗?</label></span>
-    <span slot="sub-title">删除之后不能,描述信息,删除之后不能,描述信息</span>
-</nut-actionsheet>
+<nut-actionsheet
+@close="switchActionSheet"
+        :is-visible="state.isVisible4"
+        cancelTxt="取消"
+        :menu-items="menuItemsThree"
+      ></nut-actionsheet>
 ```
 ```javascript
-export default {
-    data() {
-        return {
-            sex: '请选择',
-            isVisible: false,
-            menuItems: [
-                {
-                     'name': '确定'
-                }
-            ]
-        };
-    },
-    methods: {
-        switchActionSheet() {
-            this.isVisible = !this.isVisible;
-        },
 
-        choose(itemParams) {
-            
-        }
-    }
-};
 ```
 
 ## 自定义内容
@@ -233,31 +75,51 @@ export default {
 </nut-actionsheet>
 ```
 ```javascript
+setup() {
+    const state = reactive({
+      isVisible: false,
+      value: '',
+      desc: '这是一段描述信息'
+    });
+    const menuItems = [
+      {
+        name: '选项一',
+        value: 0
+      },
+      {
+        name: '选项二',
+        value: 1
+      },
+      {
+        name: '选项三',
+        value: 2
+      }
+    ];
+    const menuItemsStatus = [
+      {
+        name: '着色选项',
+        color: '#ee0a24',
+        value: 0
+      },
+      {
+        name: '禁用选项',
+        disable: true,
+        value: 1
+      }
+    ];
+     const switchActionSheet = () => {
+       state.isVisible = !state.isVisible
+    };
+    const chooseItem = (item,index) => {
+      console.log(item,index);
+    };
 
-export default {
-    data() {
-        return {
-            isVisible: false
-        }   
-    },
-    methods: {
-        switchActionSheet() {
-            this.isVisible = !this.isVisible;
-        }
-    }
-};
 ```
 
 ## Prop
 
 | 字段 | 说明 | 类型 | 默认值
 |----- | ----- | ----- | ----- 
-| is-animation | 是否开启动画 | Boolean | true
-| is-lock-bg-scroll | 是否锁定背景滚动 | Boolean | false
-| is-visible | 是否可见 | Boolean | false
-| is-show-mask | 是否显示背景遮罩 | Boolean | true
-| is-click-choose-close | 是否点击列表项后立即关闭 | Boolean | true
-| is-click-close-mask | 是否点击mask蒙层关闭 | Boolean | true
 | cancel-txt | 取消文案 | String | '取消'
 | choose-tag-value | 已选值,如果填写,高亮显示 | String | -
 | menu-items | 列表项 | Array | [ ]

+ 55 - 66
src/packages/actionsheet/index.scss

@@ -1,82 +1,71 @@
 .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;
-}
-
-.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 {
+    padding: 10px;
+    margin: 0;
+    text-align: center;
+    background-color: #fff;
+    border-bottom: 1px solid $light-color;
     font-size: $font-size-base;
     color: $title-color;
   }
 
-  .nut-actionsheet-sub-title {
-    font-size: $font-size-small;
-    color: $title-color;
-    margin-inline-start: 0px;
+  .nut-actionsheet-modal {
+    .nut-actionsheet-title,
+    .nut-actionsheet-sub-title {
+      padding: 5px 0;
+    }
+
+    .nut-actionsheet-sub-title {
+      font-size: $font-size-small;
+      color: $title-color;
+      margin-inline-start: 0px;
+    }
   }
-}
 
-.nut-actionsheet-menu {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
+  .nut-actionsheet-menu {
+    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;
-}
+  .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;
+  }
 
-.desc {
-  font-size: 14px;
-  color: #999;
-}
+  .desc {
+    font-size: 14px;
+    color: #999;
+  }
 
-.subdesc {
-  display: block;
-  font-size: 12px;
-  color: #999;
-}
+  .subdesc {
+    display: block;
+    font-size: 12px;
+    color: #999;
+  }
 
-.nut-actionsheet-item {
-  border-bottom: 1px solid $light-color;
-  cursor: pointer;
-}
+  .nut-actionsheet-item {
+    // border-bottom: 1px solid $light-color;
+    cursor: pointer;
+  }
 
-.nut-actionsheet-item-active {
-  color: $primary-color;
-}
+  .nut-actionsheet-item-active {
+    color: $primary-color;
+  }
 
-.nut-actionsheet-item-disabled {
-  color: #e1e1e1;
-  cursor: not-allowed;
-}
+  .nut-actionsheet-item-disabled {
+    color: #e1e1e1;
+    cursor: not-allowed;
+  }
 
-.nut-actionsheet-cancel {
-  margin-top: 5px;
-  border-top: 1px solid $light-color;
+  .nut-actionsheet-cancel {
+    margin-top: 5px;
+    border-top: 1px solid $light-color;
+  }
 }

+ 29 - 40
src/packages/actionsheet/index.vue

@@ -4,50 +4,39 @@
       v-model:show="state.maskIsVisible"
       position="bottom"
       round
+      :closeable="closeAbled"
       @click-overlay="closeMask"
     >
       <view class="nut-actionsheet-panel">
-        <view class="nut-actionsheet-custom">
-          <slot name="custom"></slot>
-        </view>
-        <dl
-          class="nut-actionsheet-modal"
-          v-if="$slots.title || $slots.subTitle"
-        >
-          <dt class="nut-actionsheet-title"><slot name="title"></slot></dt>
-          <dd class="nut-actionsheet-sub-title"
-            ><slot name="sub-title"></slot
-          ></dd>
-        </dl>
-        <ul class="nut-actionsheet-menu">
-          <li class="nut-actionsheet-item desc" v-if="description">{{
+        <view v-if="title" class="nut-actionsheet-title">{{ title }}</view>
+        <slot></slot>
+        <view class="nut-actionsheet-menu">
+          <view class="nut-actionsheet-item desc" v-if="description">{{
             description
-          }}</li>
-          <li
+          }}</view>
+          <view
+            v-for="(item, index) of menuItems"
             class="nut-actionsheet-item"
-            :class="{
-              'nut-actionsheet-item-disabled': item.disable
-            }"
+            :class="{ 'nut-actionsheet-item-disabled': item.disable }"
             :style="{ color: isHighlight(item) }"
-            v-for="(item, index) of menuItems"
             :key="index"
             @click="chooseItem(item, index)"
             >{{ item[optionTag]
-            }}<view class="subdesc">{{ item.subname }}</view></li
+            }}<view class="subdesc">{{ item[subname] }}</view></view
           >
-        </ul>
-        <div
+        </view>
+        <view
           class="nut-actionsheet-cancel"
           v-if="cancelTxt"
           @click="cancelActionSheet"
-          >{{ cancelTxt }}</div
         >
+          {{ cancelTxt }}
+        </view>
       </view>
     </nut-popup>
   </view>
 </template>
 <script>
-import Popup from '@/packages/popup/index.vue';
 import { createComponent } from '@/utils/create';
 import { watch, reactive } from 'vue';
 const { create } = createComponent('actionsheet');
@@ -73,6 +62,14 @@ export default create({
       type: String,
       default: ''
     },
+    title: {
+      type: String,
+      default: ''
+    },
+    closeAbled: {
+      type: Boolean,
+      default: false
+    },
     description: {
       type: String,
       default: ''
@@ -88,27 +85,27 @@ export default create({
   },
   emits: ['click', 'close', 'cancel', 'choose'],
 
-  setup(props, { emit }) {
-    console.log(props.isVisible, 'props.isVisible');
+  setup(props, { slots, emit }) {
+    console.log(slots.default?.());
+
     // state
     const state = reactive({
-      maskIsVisible: false
+      maskIsVisible: false,
+      descf: slots.default
     });
 
     // methods
     const isHighlight = item => {
       return item.color;
     };
-
     const closeActionSheet = () => {
       state.maskIsVisible = false;
-      //   console.log(state.maskIsVisible, 'mask');
-      emit('close');
+      // emit('close');
     };
 
     const cancelActionSheet = () => {
       closeActionSheet();
-      emit('cancel');
+      // emit('cancel');
     };
 
     const chooseItem = (item, index) => {
@@ -123,17 +120,9 @@ export default create({
     watch(
       () => props.isVisible,
       () => {
-        console.log(props.isVisible, 'val');
         state.maskIsVisible = true;
       }
-      // val => {
-      //   console.log(val, 'val');
-      //   if (val) {
-      //     state.maskIsVisible = true;
-      //   }
-      // }
     );
-
     return {
       isHighlight,
       closeActionSheet,

+ 89 - 0
src/packages/drag/demo.vue

@@ -0,0 +1,89 @@
+<template>
+  <div class="demo full">
+    <h2>基础用法</h2>
+    <nut-drag :style="{ top: '100px', left: '8px' }">
+      <div class="drag-demo">触摸移动</div>
+    </nut-drag>
+    <!-- <h2>限制拖拽方向</h2>
+    <nut-drag direction="x"  >
+      <div class="drag-demo">只能X轴拖拽</div>
+    </nut-drag>
+    <nut-drag direction="y"  >
+      <div class="drag-demo">只能Y轴拖拽</div>
+    </nut-drag> -->
+    <div class="drag" ref="drag" @touchstart="touchstart($event)">拖拽测试</div>
+  </div>
+</template>
+
+<script lang="ts">
+import { ref, reactive, toRefs, watch } from 'vue';
+import { createComponent } from '@/utils/create';
+const { createDemo } = createComponent('drag');
+export default createDemo({
+  setup() {
+    const drag = ref();
+    const state = reactive({
+      infoX: 0,
+      infoY: 0
+    });
+    function touchMove(e: { currentTarget: any; targetTouches: any[] }) {
+      const target = e.currentTarget;
+      const element = e.targetTouches[0];
+      console.log(element.clientX, element.clientY, state.infoX, state.infoY);
+      const x = element.clientX - state.infoX;
+      const y = element.clientY - state.infoY;
+      console.log(x, y);
+      element.target.style.cssText = `transform: translate3d(${x}px, ${y}px ,1px);`;
+      //  element.target.style.transform= `translate(${x}px, ${y}px)`
+    }
+    function touchEnd(e) {
+      // e.target.style.cssText = `transform: none;`
+    }
+    function touchstart(e: {
+      targetTouches: any[];
+      target: { offsetTop: any };
+    }) {
+      const element = e.targetTouches[0];
+      state.infoX = element.clientX;
+      state.infoY = element.clientY;
+      console.log(e.target.offsetTop);
+      // console.log(state.infoX,state.infoY)
+      // console.log(element.clientX,state.infoX,element.clientY,state.infoY)
+      drag.value.addEventListener('touchmove', touchMove, false);
+      drag.value.addEventListener('touchend', touchEnd, false);
+    }
+    return {
+      drag,
+      state,
+      touchstart,
+      touchMove,
+      touchEnd
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.drag-demo {
+  width: 148px;
+  height: 35px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: linear-gradient(
+    135deg,
+    rgba(250, 44, 25, 1) 0%,
+    rgba(250, 63, 25, 1) 45%,
+    rgba(250, 89, 25, 1) 83%,
+    rgba(250, 100, 25, 1) 100%
+  );
+  border-radius: 24px;
+}
+.drag {
+  width: 100px;
+  height: 100px;
+  display: inline-block;
+  background: red;
+  transform: translate3d(0, 0, 1px);
+}
+</style>

+ 0 - 0
src/packages/drag/doc.md


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

@@ -0,0 +1,7 @@
+.nut-drag {
+  position: fixed;
+  display: inline-block;
+  z-index: 9997 !important;
+  width: fit-content;
+  height: fit-content;
+}

+ 197 - 0
src/packages/drag/index.vue

@@ -0,0 +1,197 @@
+<template>
+  <view class="nut-drag" ref="myDrag" @touchstart="touchstart($event)">
+    <slot></slot>
+  </view>
+</template>
+
+<script lang="ts">
+import { onMounted, reactive, ref, watch } from 'vue';
+import { createComponent } from '@/utils/create';
+const { create } = createComponent('drag');
+export default create({
+  props: {
+    attract: {
+      type: Boolean,
+      default: false
+    },
+    direction: {
+      type: String,
+      default: 'all'
+    },
+    zIndex: {
+      type: [Number, String],
+      default: 11
+    },
+    boundary: {
+      type: Object,
+      default: function() {
+        return {
+          top: 0,
+          left: 0,
+          right: 0,
+          bottom: 0
+        };
+      }
+    }
+  },
+  setup(props: any, { emit }) {
+    const myDrag = ref();
+    console.log(props.direction);
+    const state = reactive({
+      elWidth: 0, // 元素的宽度
+      elHeight: 0, // 元素的高度
+      screenWidth: 0, // 屏幕的宽度
+      screenHeight: 0, // 屏幕的高度
+      startTop: 0, // 拖拽元素距离顶部的距离
+      startLeft: 0, // 拖拽元素距离
+      nx: 0,
+      ny: 0,
+      xPum: 0,
+      yPum: 0,
+      direction: props.direction,
+      position: { x: 0, y: 0 },
+      boundary: {
+        top: 0,
+        left: 0,
+        right: 0,
+        bottom: 0
+      }
+    });
+
+    function getInfo() {
+      const domElem = document.documentElement;
+      state.elWidth = myDrag.value.offsetWidth;
+      state.elHeight = myDrag.value.offsetHeight;
+      state.screenWidth = domElem.clientWidth;
+      state.screenHeight = domElem.clientHeight;
+      console.log(
+        domElem.clientWidth,
+        domElem.clientHeight,
+        myDrag.value.offsetWidth,
+        domElem.offsetHeight
+      );
+    }
+
+    function goLeft(target) {
+      if (state.boundary.left) {
+        if (target.style.left.split('px')[0] > state.boundary.left) {
+          target.style.left = target.style.left.split('px')[0] - 10 + 'px';
+          goLeft(target);
+        } else {
+          target.style.left = `${state.boundary.left}px`;
+        }
+      } else {
+        if (target.style.left.split('px')[0] > 10) {
+          target.style.left = target.style.left.split('px')[0] - 10 + 'px';
+          goLeft(target);
+        } else {
+          target.style.left = '0px';
+        }
+      }
+    }
+    function goRight(target, rightLocation) {
+      if (rightLocation - parseInt(target.style.left.split('px')[0]) > 10) {
+        target.style.left =
+          parseInt(target.style.left.split('px')[0]) + 10 + 'px';
+        goRight(target, rightLocation);
+      } else {
+        target.style.left = rightLocation + 'px';
+      }
+    }
+    function touchMove(e) {
+      e.preventDefault();
+      const target = e.currentTarget;
+      if (e.targetTouches.length == 1) {
+        const touch = e.targetTouches[0];
+        state.nx = touch.clientX - state.position.x;
+        state.ny = touch.clientY - state.position.y;
+        state.xPum = state.startLeft + state.nx;
+        state.yPum = state.startTop + state.ny;
+        // console.log(state.xPum,state.yPum)
+        const rightLocation =
+          state.screenWidth - state.elWidth - state.boundary.right;
+        // console.log(rightLocation)
+        // 限制左右拖拽边界
+        if (Math.abs(state.xPum) > rightLocation) {
+          state.xPum = rightLocation;
+        } else if (state.xPum <= state.boundary.left) {
+          state.xPum = state.boundary.left;
+        }
+        // 限制上下拖拽边界
+        if (state.yPum < state.boundary.top) {
+          state.yPum = state.boundary.top;
+        } else if (
+          state.yPum >
+          state.screenHeight - state.elHeight - state.boundary.bottom
+        ) {
+          state.yPum =
+            state.screenHeight - state.elHeight - state.boundary.bottom;
+        }
+        if (props.direction != 'y') {
+          console.log('121');
+          target.style.left = state.xPum + 'px';
+        }
+        if (props.direction != 'x') {
+          console.log('121121');
+          target.style.top = state.yPum + 'px';
+        }
+      }
+    }
+    function touchEnd(e) {
+      const target = e.currentTarget;
+      const touch = e.changedTouches[0];
+      let currX = touch.clientX;
+      const rightLocation =
+        state.screenWidth - state.elWidth - state.boundary.right;
+      if (currX > rightLocation) {
+        currX = rightLocation;
+        // console.log('往右划出边界');
+      } else if (currX < state.boundary.left) {
+        currX = state.boundary.left;
+        // console.log('往左划出边界');
+      } else {
+        currX =
+          currX < state.screenWidth / 2 ? state.boundary.left : rightLocation;
+        // console.log('在边界内滑动');
+      }
+      if (state.direction != 'y' && props.attract) {
+        if (currX < state.screenWidth / 2) {
+          goLeft(target);
+        } else {
+          goRight(target, rightLocation);
+        }
+      }
+      if (state.direction != 'x') {
+        target.style.top = state.yPum + 'px';
+      }
+    }
+    function touchstart(e) {
+      const target = e.currentTarget;
+      state.startTop = target.offsetTop; // 元素距离顶部的距离
+      state.startLeft = target.offsetLeft; // 元素距离左侧的距离
+      state.position.x = e.touches[0].clientX; // 鼠标点击的x轴的距离
+      state.position.y = e.touches[0].clientY; // 鼠标点击的y轴的距离
+      myDrag.value.addEventListener('touchmove', touchMove, false);
+      myDrag.value.addEventListener('touchend', touchEnd, false);
+    }
+    onMounted(() => {
+      getInfo();
+      state.boundary = props.boundary;
+    });
+    return {
+      state,
+      touchstart,
+      myDrag,
+      touchMove,
+      touchEnd,
+      getInfo,
+      goLeft,
+      goRight
+    };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 2 - 2
src/sites/doc/views/Main.vue

@@ -6,8 +6,8 @@
       <div class="content-smile"> </div>
       <div class="content-subTitle">一款具有京东风格的VUE组件</div>
       <div class="content-button">
-        <div class="leftButton">
-          <div class="leftButtonText" @click="toIntro">开始使用</div>
+        <div class="leftButton" @click="toIntro">
+          <div class="leftButtonText">开始使用</div>
         </div>
         <div class="rightButton">
           <div class="rightButtonText">扫码体验</div>