Skip to content

插件和第三方库 - 站在巨人的肩膀上

🔧 不要重复造轮子!今天我们来学习如何使用现成的插件和库来提高开发效率

1. UniApp插件市场

插件市场介绍

UniApp插件市场是官方提供的插件生态平台,包含:

  • UI组件库
  • 功能插件
  • 模板项目
  • 原生插件

访问地址:https://ext.dcloud.net.cn/

安装插件的方式

方式1:HBuilderX导入

  1. 在插件市场找到需要的插件
  2. 点击"使用HBuilderX导入插件"
  3. 选择项目导入

方式2:手动下载

  1. 下载插件压缩包
  2. 解压到项目的uni_modules目录

方式3:npm安装

bash
npm install @dcloudio/uni-ui

2. 常用UI组件库

uni-ui官方组件库

bash
# 安装uni-ui
npm install @dcloudio/uni-ui
vue
<template>
  <view class="uni-ui-demo">
    <!-- 数字角标 -->
    <uni-badge text="99+" type="error">
      <button>消息</button>
    </uni-badge>
    
    <!-- 卡片 -->
    <uni-card title="卡片标题" sub-title="副标题" extra="额外信息">
      <text>卡片内容</text>
    </uni-card>
    
    <!-- 折叠面板 -->
    <uni-collapse>
      <uni-collapse-item title="面板1" open>
        <text>面板1的内容</text>
      </uni-collapse-item>
      <uni-collapse-item title="面板2">
        <text>面板2的内容</text>
      </uni-collapse-item>
    </uni-collapse>
    
    <!-- 倒计时 -->
    <uni-countdown 
      :time="countdownTime"
      @timeup="onTimeup"
    />
    
    <!-- 抽屉 -->
    <uni-drawer ref="drawer" mode="left" width="300">
      <view class="drawer-content">
        <text>抽屉内容</text>
      </view>
    </uni-drawer>
    
    <button @click="openDrawer">打开抽屉</button>
    
    <!-- 悬浮按钮 -->
    <uni-fab 
      :pattern="fabPattern"
      @trigger="onFabClick"
    />
  </view>
</template>

<script>
export default {
  data() {
    return {
      countdownTime: 60000, // 60秒
      fabPattern: {
        color: '#007aff',
        backgroundColor: '#fff',
        selectedColor: '#fff',
        buttonColor: '#007aff',
        iconColor: '#fff',
        content: [
          {
            iconPath: '/static/add.png',
            selectedIconPath: '/static/add-active.png',
            text: '添加',
            active: false
          },
          {
            iconPath: '/static/share.png',
            selectedIconPath: '/static/share-active.png',
            text: '分享',
            active: false
          }
        ]
      }
    }
  },
  methods: {
    onTimeup() {
      uni.showToast({
        title: '倒计时结束',
        icon: 'success'
      })
    },
    openDrawer() {
      this.$refs.drawer.open()
    },
    onFabClick(e) {
      console.log('悬浮按钮点击:', e)
    }
  }
}
</script>

<style>
.uni-ui-demo {
  padding: 20rpx;
}
.drawer-content {
  padding: 30rpx;
  height: 100vh;
  background: #f8f9fa;
}
</style>

uView UI组件库

bash
# 安装uView
npm install uview-ui
javascript
// main.js
import uView from 'uview-ui'
Vue.use(uView)
vue
<template>
  <view class="uview-demo">
    <!-- 按钮 -->
    <u-button type="primary" @click="handleClick">主要按钮</u-button>
    <u-button type="success" shape="circle">圆形按钮</u-button>
    
    <!-- 输入框 -->
    <u-input 
      v-model="inputValue" 
      placeholder="请输入内容"
      border="bottom"
    />
    
    <!-- 选择器 -->
    <u-picker 
      :show="showPicker"
      :columns="pickerColumns"
      @confirm="onPickerConfirm"
      @cancel="showPicker = false"
    />
    
    <!-- 步骤条 -->
    <u-steps :list="stepsList" :current="currentStep" />
    
    <!-- 标签 -->
    <u-tag text="标签1" type="primary" />
    <u-tag text="标签2" type="success" closable />
    
    <!-- 时间轴 -->
    <u-timeline>
      <u-timeline-item title="订单创建" content="2024-01-01 10:00" />
      <u-timeline-item title="订单支付" content="2024-01-01 10:05" />
      <u-timeline-item title="订单发货" content="2024-01-01 14:00" />
    </u-timeline>
  </view>
</template>

<script>
export default {
  data() {
    return {
      inputValue: '',
      showPicker: false,
      pickerColumns: [
        ['北京', '上海', '广州', '深圳']
      ],
      stepsList: [
        { name: '下单' },
        { name: '支付' },
        { name: '发货' },
        { name: '收货' }
      ],
      currentStep: 1
    }
  },
  methods: {
    handleClick() {
      this.showPicker = true
    },
    onPickerConfirm(value) {
      console.log('选择结果:', value)
      this.showPicker = false
    }
  }
}
</script>

3. 实用功能插件

图表插件 - uCharts

bash
# 安装uCharts
npm install @qiun/ucharts
vue
<template>
  <view class="charts-demo">
    <canvas 
      canvas-id="lineChart" 
      id="lineChart"
      class="chart-canvas"
      @touchstart="touchChart"
      @touchmove="touchChart"
      @touchend="touchChart"
    />
    
    <canvas 
      canvas-id="pieChart" 
      id="pieChart"
      class="chart-canvas"
    />
  </view>
</template>

<script>
import uCharts from '@qiun/ucharts'

export default {
  data() {
    return {
      lineChart: null,
      pieChart: null
    }
  },
  
  onReady() {
    this.initLineChart()
    this.initPieChart()
  },
  
  methods: {
    initLineChart() {
      const chartData = {
        categories: ['1月', '2月', '3月', '4月', '5月', '6月'],
        series: [
          {
            name: '销售额',
            data: [35, 20, 25, 37, 4, 20]
          },
          {
            name: '利润',
            data: [15, 10, 12, 18, 2, 8]
          }
        ]
      }
      
      this.lineChart = new uCharts({
        type: 'line',
        context: uni.createCanvasContext('lineChart', this),
        width: 350,
        height: 250,
        categories: chartData.categories,
        series: chartData.series,
        animation: true,
        background: '#FFFFFF',
        color: ['#1890FF', '#91CB74'],
        padding: [15, 15, 0, 15],
        legend: {
          show: true,
          position: 'bottom',
          float: 'center',
          backgroundColor: 'rgba(0,0,0,0)',
          borderColor: 'rgba(0,0,0,0)',
          fontColor: '#666666',
          fontSize: 13,
          margin: 5
        },
        xAxis: {
          disableGrid: false,
          gridType: 'dash',
          fontColor: '#666666'
        },
        yAxis: {
          gridType: 'dash',
          splitNumber: 5,
          min: 0,
          fontColor: '#666666',
          format: (val) => val.toFixed(0)
        },
        extra: {
          line: {
            type: 'curve',
            width: 2,
            activeType: 'hollow'
          }
        }
      })
    },
    
    initPieChart() {
      const chartData = {
        series: [
          { name: 'iOS', data: 50 },
          { name: 'Android', data: 30 },
          { name: 'Web', data: 20 }
        ]
      }
      
      this.pieChart = new uCharts({
        type: 'pie',
        context: uni.createCanvasContext('pieChart', this),
        width: 350,
        height: 250,
        series: chartData.series,
        animation: true,
        background: '#FFFFFF',
        color: ['#1890FF', '#91CB74', '#FAC858'],
        padding: [5, 5, 5, 5],
        legend: {
          show: true,
          position: 'right',
          float: 'middle'
        },
        extra: {
          pie: {
            activeOpacity: 0.5,
            activeRadius: 10,
            offsetAngle: 0,
            labelWidth: 15,
            border: true,
            borderWidth: 3,
            borderColor: '#FFFFFF'
          }
        }
      })
    },
    
    touchChart(e) {
      if (this.lineChart) {
        this.lineChart.showToolTip(e, {
          format: function (item, category) {
            return category + ' ' + item.name + ':' + item.data
          }
        })
      }
    }
  }
}
</script>

<style>
.charts-demo {
  padding: 20rpx;
}
.chart-canvas {
  width: 350px;
  height: 250px;
  margin: 20rpx auto;
  border: 1px solid #eee;
}
</style>

二维码插件

vue
<template>
  <view class="qrcode-demo">
    <button @click="generateQRCode">生成二维码</button>
    <button @click="scanQRCode">扫描二维码</button>
    
    <canvas 
      v-if="showQRCode"
      canvas-id="qrcode" 
      class="qrcode-canvas"
    />
    
    <view v-if="scanResult" class="scan-result">
      <text>扫描结果:\{\{ scanResult \}\}</text>
    </view>
  </view>
</template>

<script>
import QRCode from '@/uni_modules/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js'

export default {
  data() {
    return {
      showQRCode: false,
      scanResult: ''
    }
  },
  
  methods: {
    generateQRCode() {
      this.showQRCode = true
      
      this.$nextTick(() => {
        QRCode.make({
          canvasId: 'qrcode',
          componentInstance: this,
          text: 'https://www.example.com',
          size: 200,
          margin: 10,
          backgroundColor: '#ffffff',
          foregroundColor: '#000000',
          fileType: 'jpg',
          errorCorrectLevel: QRCode.errorCorrectLevel.M,
          success: (res) => {
            console.log('二维码生成成功:', res)
          }
        })
      })
    },
    
    scanQRCode() {
      uni.scanCode({
        success: (res) => {
          this.scanResult = res.result
          uni.showToast({
            title: '扫描成功',
            icon: 'success'
          })
        },
        fail: (err) => {
          console.error('扫描失败:', err)
          uni.showToast({
            title: '扫描失败',
            icon: 'error'
          })
        }
      })
    }
  }
}
</script>

<style>
.qrcode-demo {
  padding: 20rpx;
  text-align: center;
}
.qrcode-demo button {
  margin: 20rpx;
  width: 300rpx;
}
.qrcode-canvas {
  width: 200px;
  height: 200px;
  margin: 20rpx auto;
  border: 1px solid #eee;
}
.scan-result {
  margin-top: 30rpx;
  padding: 20rpx;
  background: #f8f9fa;
  border-radius: 8rpx;
}
</style>

4. 工具类库

日期处理 - dayjs

bash
npm install dayjs
javascript
// utils/date.js
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import 'dayjs/locale/zh-cn'

dayjs.extend(relativeTime)
dayjs.locale('zh-cn')

export default {
  // 格式化日期
  format(date, format = 'YYYY-MM-DD HH:mm:ss') {
    return dayjs(date).format(format)
  },
  
  // 相对时间
  fromNow(date) {
    return dayjs(date).fromNow()
  },
  
  // 是否是今天
  isToday(date) {
    return dayjs(date).isSame(dayjs(), 'day')
  },
  
  // 是否是本周
  isThisWeek(date) {
    return dayjs(date).isSame(dayjs(), 'week')
  },
  
  // 获取月份天数
  daysInMonth(date) {
    return dayjs(date).daysInMonth()
  },
  
  // 添加时间
  add(date, value, unit) {
    return dayjs(date).add(value, unit)
  },
  
  // 减少时间
  subtract(date, value, unit) {
    return dayjs(date).subtract(value, unit)
  }
}

数据验证 - async-validator

bash
npm install async-validator
javascript
// utils/validator.js
import Schema from 'async-validator'

export default class Validator {
  constructor(rules) {
    this.schema = new Schema(rules)
  }
  
  validate(data) {
    return new Promise((resolve, reject) => {
      this.schema.validate(data, (errors, fields) => {
        if (errors) {
          reject({ errors, fields })
        } else {
          resolve(data)
        }
      })
    })
  }
}

// 常用验证规则
export const commonRules = {
  required: { required: true, message: '此字段为必填项' },
  email: { type: 'email', message: '请输入正确的邮箱地址' },
  phone: { 
    pattern: /^1[3-9]\d{9}$/, 
    message: '请输入正确的手机号码' 
  },
  password: {
    min: 6,
    max: 20,
    message: '密码长度应在6-20位之间'
  }
}

使用验证器

vue
<template>
  <view class="form-validation">
    <view class="form-group">
      <input 
        v-model="formData.username"
        placeholder="用户名"
        :class="{ error: errors.username }"
      />
      <text v-if="errors.username" class="error-text">
        \{\{ errors.username \}\}
      </text>
    </view>
    
    <view class="form-group">
      <input 
        v-model="formData.email"
        placeholder="邮箱"
        :class="{ error: errors.email }"
      />
      <text v-if="errors.email" class="error-text">
        \{\{ errors.email \}\}
      </text>
    </view>
    
    <view class="form-group">
      <input 
        v-model="formData.phone"
        placeholder="手机号"
        :class="{ error: errors.phone }"
      />
      <text v-if="errors.phone" class="error-text">
        \{\{ errors.phone \}\}
      </text>
    </view>
    
    <button @click="handleSubmit" :disabled="isSubmitting">
      \{\{ isSubmitting ? '提交中...' : '提交' \}\}
    </button>
  </view>
</template>

<script>
import Validator, { commonRules } from '@/utils/validator.js'

export default {
  data() {
    return {
      formData: {
        username: '',
        email: '',
        phone: ''
      },
      errors: {},
      isSubmitting: false,
      validator: new Validator({
        username: [
          commonRules.required,
          { min: 3, max: 20, message: '用户名长度应在3-20位之间' }
        ],
        email: [
          commonRules.required,
          commonRules.email
        ],
        phone: [
          commonRules.required,
          commonRules.phone
        ]
      })
    }
  },
  
  methods: {
    async handleSubmit() {
      this.errors = {}
      this.isSubmitting = true
      
      try {
        await this.validator.validate(this.formData)
        
        // 验证通过,提交数据
        await this.submitForm()
        
        uni.showToast({
          title: '提交成功',
          icon: 'success'
        })
      } catch ({ errors, fields }) {
        // 验证失败,显示错误信息
        this.errors = {}
        errors.forEach(error => {
          this.errors[error.field] = error.message
        })
        
        uni.showToast({
          title: '请检查表单信息',
          icon: 'error'
        })
      } finally {
        this.isSubmitting = false
      }
    },
    
    async submitForm() {
      // 模拟提交
      return new Promise(resolve => {
        setTimeout(resolve, 1000)
      })
    }
  }
}
</script>

<style>
.form-validation {
  padding: 20rpx;
}
.form-group {
  margin-bottom: 30rpx;
}
.form-group input {
  width: 100%;
  padding: 20rpx;
  border: 1rpx solid #ddd;
  border-radius: 8rpx;
  font-size: 28rpx;
}
.form-group input.error {
  border-color: #ff3b30;
}
.error-text {
  color: #ff3b30;
  font-size: 24rpx;
  margin-top: 8rpx;
  display: block;
}
</style>

5. 插件开发

创建自定义插件

javascript
// uni_modules/my-plugin/index.js
const MyPlugin = {
  install(Vue, options = {}) {
    // 添加全局方法
    Vue.prototype.$myMethod = function(message) {
      uni.showToast({
        title: message,
        icon: 'none'
      })
    }
    
    // 添加全局指令
    Vue.directive('highlight', {
      bind(el, binding) {
        el.style.backgroundColor = binding.value || 'yellow'
      }
    })
    
    // 添加全局混入
    Vue.mixin({
      created() {
        if (options.debug) {
          console.log('组件创建:', this.$options.name)
        }
      }
    })
  }
}

export default MyPlugin

使用自定义插件

javascript
// main.js
import MyPlugin from '@/uni_modules/my-plugin/index.js'

Vue.use(MyPlugin, {
  debug: true
})

小结

今天我们学习了:

  • ✅ UniApp插件市场的使用
  • ✅ 常用UI组件库的集成
  • ✅ 实用功能插件的应用
  • ✅ 工具类库的使用
  • ✅ 自定义插件的开发

插件使用要点

  • 选择活跃度高、文档完善的插件
  • 注意插件的兼容性和性能影响
  • 合理评估插件的必要性
  • 学会阅读插件文档和源码

下一篇预告

下一篇我们将学习《性能优化技巧 - 让你的小程序跑得更快》,学习各种性能优化的方法和技巧。


站在巨人的肩膀上,我们能看得更远!合理使用插件和库,能让开发事半功倍!