标签 - JavaScript 共找到结果 17 条

一次Vue项目中需求本来是单选的级联选择器,本来很简单因为iView组件里有,结果产品更改需求到要求实现Vue多选级联选择器,先在网上找了一下想偷个懒结果发现没有,所以这算奇葩需求吗 hah

cascader-multi

基于iView-Cascader的多选级联选择器

效果预览

install 安装

npm i cascader-multi --save

use 使用

在main.js中写入下面的代码

import cascaderMulti from "cascader-multi";
Vue.use(cascaderMulti);

接下来,你就可以在页面中使用cascader-multi了

<template>
    <cascaderMulti @on-change="array => end_code = array" :data="end_codes" placeholder="状态码"></cascaderMulti>
</template>
<script>
    export default {
        data () {
            return {
                end_code: [],
                end_codes: []
            }
        }
    }
</script>
属性 说明 类型 默认值
data 用于渲染页面的数据 Array
value 默认已选择数据项 Array
multiple 是否支持多选 Boolean false
filterable 是否支持搜索 Boolean true
disabled 是否禁用选择器 Boolean false
clearable 是否支持清除 Boolean true
size 输入框大小,可选值为largesmall或者不填 String -
transfer 是否将弹层放置于 body 内,在 Tabs、带有 fixed 的 Table 列内使用时,建议添加此属性,它将不受父级样式影响,从而达到更好的效果 Boolean false
placeholder 输入框占位符 String -
element-id 给表单元素设置 id,详见 iView-Form 用法。 String -
name 给表单元素设置 name,详见 iView-Form 用法。 String -
事件 说明 返回值
on-change 选择完成后的回调,返回值此时已选的数据数组 data

补充说明

  • 传入data数据格式如下:
    [
      {
        value: 1000,
        label: "接通",
        children: [{
          label: "已报价",
          value: 1100,
          children: [],
          multiple: true //可忽略项,当为true时该项为多选
        }]
      }
    ]
    

文件目录

.
├── README.md
├── dist
│   ├── cascader-multi.js
│   └── cascader-multi.js.map
├── package-lock.json
├── package.json
├── src
│   ├── index.js
│   └── lib
│       ├── components
│       │   ├── cascader-multi-panel.vue
│       │   ├── cascader-multi.vue
│       │   └── index.js
│       └── utils
│           └── index.js
└── webpack.config.js

代码已上传至:

阅读全文

近期手上有个小程序项目,UI妹纸给的对话框效果图需要自定义,因为wx.showModal无法自定义内容,例如icon图标,字体大小之类的,只能自定义一个Modal组件。

下面是自定义组件的文件:

1. dialogModal.js


Component({
  properties: {
    // 模态框 显示/隐藏
    modalHidden: {
      type: Boolean,
      value: false
    }, //这里定义了modalHidden属性,属性值可以在组件使用时指定.写法为modal-hidden,
    showCancel: {
      type: Boolean,
      value: true
    },
    // 模态框title标题
    modalTitle: {
      type: String,
      value: '',
    },
    // 模态框msg内容
    modalMsg: {
      type: String,
      value: ''
    },
    // 模态框状态 1.‘’;2.‘success’;3.‘error’
    modalType: {
      type: String,
      value: ''
    }
  },
  methods: {
    // 防止事件冒泡,阻止page滚动事件
    moveD: () => { },
    // modal取消点击事件
    modal_cancel: function () {
      // 隐藏模态框
      this.setData({
        modalHidden: true,
      })
    },
    // modal确认点击事件
    modal_confirm: function (e) {
      this.modal_cancel();
      var eventDetail = {} // detail对象,提供给事件监听函数
      var eventOption = {} // 触发事件的选项
      this.triggerEvent('handleConfirm');
    }
  }
})

2. dialogModal.json

{
  "component": true,
  "usingComponents": {}
}

3. dialogModal.wxml

<!--components/dialogModal/dialogModal.wxml-->
<view hidden='{{modalHidden}}' class="dialog-modal" catchtouchmove='moveD'>
  <view class='mask_layer' />
  <view class='modal_box'>
    <image bindtap='modal_cancel' src="../../images/modal_close.png" class="modal-close"></image>
    <view class='modal-body'>
      <view>
        <view class="modal-title">
          <image src="../../images/error.png" wx:if="{{modalType == 'error'}}"></image>
          <image src="../../images/success.png" wx:if="{{modalType == 'success'}}"></image>
          <text>{{modalTitle}}</text>
        </view>
        <!-- modal状态为'success',只显示标题 -->
        <view class="modal-content" wx:if="{{modalMsg}}">
          <text>{{modalMsg}}</text>
        </view>
      </view>
    </view>
    <view class='modal-btn'>
      <text wx:if="{{showCancel}}" bindtap='modal_cancel' class='modal-cancel'>取消</text>
      <text bindtap='modal_confirm' class='modal-confirm'>确定</text>
    </view>
  </view>
</view>

4. dialogModal.wxss

/* components/dialogModal/dialogModal.wxss */

.dialog-modal {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}

.mask_layer {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1000;
  background: #000;
  opacity: 0.5;
  overflow: hidden;
}

.modal_box {
  position: relative;
  width: 91.4%;
  overflow: hidden;
  z-index: 1001;
  background: #fff;
  border-radius: 3px;
}

.modal-close {
  position: absolute;
  right: 16rpx;
  top: 16rpx;
  width: 20rpx;
  height: 20rpx;
}

.modal-body {
  text-align: center;
  /* margin: 30rpx 0; */
  display: flex;
  overflow-y: scroll; /*超出父盒子高度可滚动*/
  min-height: 228rpx;
  justify-content: center;
  align-items: center;
  padding: 20rpx;
}

.modal-body image {
  width: 44rpx;
  /* vertical-align:-6rpx; */
  height: 44rpx;
  margin-right: 15rpx;
}

.modal-title {
  padding: 20rpx 0;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: gazure;
  font-size: 32rpx;
  color: #484848;
  letter-spacing: 0.36px;
}

.modal-content {
  padding: 20rpx 0;
  font-size: 28rpx;
  color: #484848;
  letter-spacing: 0.31px;
}

.modal-btn {
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
  background-color: #fff;
}

.modal-cancel {
  width: 100%;
  padding: 40rpx;
  text-align: center;
  border-top: 1rpx solid #f3f3f3;
  border-right: 1rpx solid #f3f3f3;
  font-size: 28rpx;
  color: #fd5612;
  letter-spacing: 0.31px;
}

.modal-confirm {
  width: 100%;
  padding: 40rpx;
  background-color: #fff;
  text-align: center;
  border-top: 1rpx solid #f3f3f3;
  font-size: 28rpx;
  color: #fd5612;
  letter-spacing: 0.31px;
}

.modal-msg {
  text-align: center;
  margin-bottom: 50rpx;
  display: block;
}

接下来就是在我们的index页面里使用自定义的Modal组件:

1. index.json

{
  "usingComponents": {
    "modal": "../../components/dialogModal/dialogModal"
  }
}

2. index.wxml

<!--index.wxml-->
<view class="container">
  <modal bind:handleConfirm="modalConfirmCallBack" modal-hidden="{{modal.hidden}}" modal-title="{{modal.title}}" modal-msg="{{modal.msg}}" modal-type="{{modal.type}}" data-params="{{modal.params}}"></modal>
  <button bindtap='handleDefaultClick'>default</button>
  <button bindtap='handleSuccessClick'>success</button>
  <button bindtap='handleErrorClick'>error</button>
</view>

3. index.js

//index.js
//获取应用实例
const app = getApp()

Page({
  data: {
    modal: {
      hidden: true,
      title: '',
      msg: '',
      type: '',
      params: {}
    }
  },
  handleDefaultClick: function () {
    this.setData({
      'modal.hidden': false,
      'modal.title': 'default标题',
      'modal.msg': 'default内容',
      'modal.type': '',
      'modal.params': {
        type: 'default'
      }
    })
  },
  handleSuccessClick: function () {
    this.setData({
      'modal.hidden': false,
      'modal.title': 'success标题',
      'modal.msg': 'success内容',
      'modal.type': 'success',
      'modal.params': {
        type: 'success'
      }
    })
  },
  handleErrorClick: function () {
    this.setData({
      'modal.hidden': false,
      'modal.title': 'error标题',
      'modal.msg': 'error内容',
      'modal.type': 'error',
      'modal.params': {
        type: 'error'
      }
    })
  },
  modalConfirmCallBack: function (e) {
    const params = e.target.dataset.params;
    console.log(params);
  }
})

4. index.wxss

/**index.wxss**/

.container button {
  margin-top: 20rpx;
}

modal {
  z-index: 1024;
}

具体代码在: mrabit/wx_app_component

参考地址:

阅读全文

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 – 维基百科

函数柯里化的好处在于:

  • 函数复用,提高适用性
  • 延迟执行

1.函数复用:

const match = (reg, str) => {
  console.log(str.match(reg));
};

const reg = /\s+/g;
// 重复调用reg变量
match(reg, 'hello world'); // [" "]
match(reg, 'spaceless'); // null

函数柯里化实现:

const curry = fn => {
  return (...args) => {
    return (...cb) => {
	  // 合并参数,立即执行
      return fn.apply(null, [...args, ...cb]);
    };
  };
};

const match = curry((reg, str) => {
  console.log(str.match(reg));
});
const hasSpace = match(/\s+/g);

hasSpace('hello world'); // [" "]
hasSpace('spaceless'); // null

缩小函数的适用范围,但同时提高函数的适用性

2.延迟执行

const curry = (fn) => {
  return (...args) => {
    return function _f() {
      if (arguments.length) {
        // 参数不为空,合并参数
        args.push(...arguments);
        // 返回自身,链式调用
        return _f;
      }
      // 参数为空,立即执行
      return fn.apply(null, args);
    };
  };
};

// 累加方法
const add = curry((...arr) => {
  return arr.reduce((next, p) => {
    return next + p;
  }, 0);
});

console.log(add(1, 2, 3, 4)(5)()); // 15
console.log(add(1)(2)(3)(4)(5)()); // 15

累积传入参数,当不传参数的时候,最后执行。

参考地址:

阅读全文

Vue构建的大多是SPA单页面应用,但有时候在实际项目中单页面应用并不一定符合业务需求

准备工作

利用vue-cli新建项目,再执行npm install命令安装所需依赖,之后需安装新依赖glob

npm install --save-dev glob

修改webpack配置

需要改动的文件都在build文件夹下:

  • util.js
  • webpack.base.conf.js
  • webpack.dev.conf.js
  • webpack.prod.conf.js

utils.js 文件

// glob是webpack安装时依赖的一个第三方模块,还模块允许你使用 *等符号
// 例如lib/*.js就是获取lib文件夹下的所有js后缀名的文件
const glob = require('glob');
// 页面模版文件路径
const page_path = path.join(__dirname, '../src/module');
// 页面模板插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 融合相应的配置
const merge = require('webpack-merge');

// 多页面入口文件配置
// 通过glob模块读取pages文件夹下的所有对应文件夹下的js后缀文件,如果该文件存在
// 那么就作为入口文件之一
exports.entry = _ => {
  var entryFiles = glob.sync(page_path + '/*/*.js');
  var map = {};
  entryFiles.map(filePath => {
      let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
      map[filename] = filePath;
  });
  return map;
}

// 多页面输出配置
// 与上面的多页面入口文件配置相同,读取pages文件夹下的对应的html后缀文件,然后放入数组中
exports.HtmlWebpackPlugin = _ => {
  var entryFiles = glob.sync(page_path + '/*/*.html');
  var arr = [];
  entryFiles.map(filePath => {
      let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
      let config = {
          // 模板来源
          template: filePath,
          // 文件名称
          filename: filename + '.html',
          inject: true,
          // 页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
          chunks: ['manifest', 'vendor', filename]
      }
      // 生产环境加入新配置,该配置是原webpack.prod.conf.js中相对于webpack.dev.conf.js新增配置
      if (process.env.NODE_ENV === 'production') {
          config = merge(config, {
              minify: {
                  removeComments: true,
                  collapseWhitespace: true,
                  removeAttributeQuotes: true
              },
              chunksSortMode: 'dependency'
          })
      }
      arr.push(new HtmlWebpackPlugin(config));
  });
  return arr;
}

webpack.base.conf.js 文件

原:

entry: {
    app: './src/main.js'
},

替换成

entry: utils.entry(),

webpack.dev.conf.js 文件

注释掉:

plugins: [
    // new HtmlWebpackPlugin({
    //     filename: 'index.html',
    //     template: 'index.html',
    //     inject: true
    // }),
]

并在

plugins: [].concat(utils.HtmlWebpackPlugin())

webpack.prod.conf.js 文件

同上注释掉:

plugins: [
    // new HtmlWebpackPlugin({
    //     filename: config.build.index,
    //     template: 'index.html',
    //     inject: true,
    //     minify: {
    //         removeComments: true,
    //         collapseWhitespace: true,
    //         removeAttributeQuotes: true
    //             // more options:
    //             // https://github.com/kangax/html-minifier#options-quick-reference
    //     },
    //     // necessary to consistently work with multiple chunks via CommonsChunkPlugin
    //     chunksSortMode: 'dependency'
    // }),
]

并在

plugins: [].concat(utils.HtmlWebpackPlugin())

至此,webpack的配置就结束了。

文件结构

.
├── README.md
├── build
│   ├── build.js
│   ├── check-versions.js
│   ├── logo.png
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   └── webpack.prod.conf.js
├── config
│   ├── dev.env.js
│   ├── index.js
│   └── prod.env.js
├── package.json
├── src
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   ├── Hello.vue
│   │   └── cell.vue
│   └── module
│       ├── cell
│       │   ├── cell.html
│       │   ├── cell.js
│       │   └── cell.vue
│       └── index
│           ├── index.html
│           ├── index.js
│           ├── index.vue
│           └── router
│               └── index.js
└── static

src为默认工程文件,其中的assets,components,module分别是静态资源文件、组件文件、页面文件。 页面文件中按照项目的模块分的文件夹,每个文件夹下分别有三个内容:vue文件,js文件和html文件。这三个文件的作用就相当于做spa单页面应用时,根目录的index.html页面模板,src文件下的main.jsapp.vue的功能。

现在可以直接运行npm start试试看效果

相关代码:

参考地址:

阅读全文

后台一直都是密码登录,简直枯燥的没朋友,看见小伙伴的博客设置的是扫描二维码登录,然后请教了一番加上自己的理解,实现了小程序配合扫码登录后台

首先是要理解扫码登录的逻辑,在我看来扫码的小程序就是superadmin,扫码就能实现后台的token生成,保存到redis,发放给前端页面,所以小程序的权限设置是很重要的,这里单独新增一个表:tp_wx,存放微信账号的唯一标识,可读可写:

OPEN_ID字段就是小程序里 wx.login 方法的返回值,用户唯一标识, 数据库里不存在该OPEN_ID的话当然是没有权限的:

下面是简单的思路:

  1. websocket连接服务端之后保存一个自定义的标识,对应相应客户端,下面把这个标识称之为key

  2. 再把这个key通过qrcode生成二维码显示到页面上等待小程序扫码读取

  3. 小程序扫码后,获取到这个key并发送给服务端

  4. 服务端再通过小程序发送的key找到对应的客户端并提示登录成功或者失败

具体代码已上传至github: websocket-wxApp-login

参考地址:

阅读全文