uniapp好用的组件

uni-app好用组件介绍

注意:以下组件需要vant weapp 和uv ui

1.下拉框

<template>
  <view>
    <view  style="width: 320rpx">
      <view class="item">
        <view class="content" @click="openPicker">
          <uv-input :placeholder="`请选择${placeholder}`" disabled disabledColor="#ffffff" clearable border="none"
                    :value="modelValue?.text"
                    placeholder-style="color: #BBBDBF">
          </uv-input>
          <view   v-if="modelValue?.text&&obj.posts[0].code!=='10005'" @click.stop.prevent="clearValue" style="display: flex;align-items: center"> <van-icon  size="26rpx" name="close" color="gray"/> </view>

          <uv-icon name="arrow-right" color="#D4D6D9" size="32rpx"></uv-icon>
        </view>
      </view>
    </view>
  </view>

  <van-popup
      :show="show"
      round
      position="bottom"
      custom-style="width: 750rpx;height: 750rpx;"
      @close="cancel"
  >
    <view style="width: 700rpx;margin-left: 25rpx;margin-top: 30rpx;" v-if="showSearch">
      <van-field
          right-icon="search"
          :value='searchName'
          :placeholder="`请输入${placeholder}搜索`"
          :maxlength="50"
          clearable
          @change="searchName=$event.detail;likeSearch()"
      >
      </van-field>
    </view>

    <van-picker
        show-toolbar
        :columns="filteredColumns"
        @confirm="onConfirm"
        @cancel="cancel"
    />
  </van-popup>
</template>

<script setup>
import { ref, defineProps, defineEmits, watch } from 'vue'

const props = defineProps({
  columns: {
    type: Array,
    default: () => []
  },
  modelValue: {
    default: undefined
  },
  placeholder: {
    type: String,
    default: ''
  },
  showSearch: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['update:modelValue'])
const show = ref(false)
const ifDisable = ref(false)
const searchName = ref('')
const originalColumns = ref([]) // 保存原始数据
const filteredColumns = ref([]) // 存储过滤后的数据
const obj = uni.getStorageSync('USER__INFO__');
// 监听 columns 变化,当数据加载完成时选中第一项
watch(() => props.columns, (newVal) => {
  if (newVal?.length) {
    originalColumns.value = [...newVal]
    filteredColumns.value = [...newVal] // 初始化过滤后的数据
    if (obj.posts[0].code==='10005') {
      emit('update:modelValue', {
        text: obj.name,
        value: obj.code,
        postId: obj.postId,
      })
    }else{
      emit('update:modelValue', {})
    }
  }
}, { immediate: true })

const openPicker = () => {
  // 员工
  if(obj.posts[0].code==='10005'){
    return
  }
  show.value = true
}

const clearValue = (event) => {
  event.stopPropagation();
  // 员工
  emit('update:modelValue', {})
}

const cancel = () => {
  show.value = false
}

const onConfirm = (e) => {
  emit('update:modelValue', e.detail.value)
  show.value = false
}

const likeSearch = () => {
  if (!searchName.value) {
    // 搜索框为空,恢复原始数据
    filteredColumns.value = [...originalColumns.value]
    return
  }

  // 实现搜索过滤逻辑
  const filteredColumn = originalColumns.value.filter(item =>
      item.text.includes(searchName.value)
  )

  filteredColumns.value = filteredColumn
  console.log('搜索结果:', filteredColumns)
}
</script>
<style scoped lang="scss">
@import '/static/sass/global.scss';
.item {
  margin-bottom: 30rpx;
  .title {
    @include setBoldFont(28rpx, 36rpx, #000000);
    margin: 10px;
  }

  .content {
    margin-top: 20rpx;
    box-sizing: border-box;
    padding: 0 16rpx;
    height: 64rpx;
    width: 100%;
    display: flex;
    background: rgba(255, 255, 255, 0.8);
    border-radius: 8rpx 8rpx 8rpx 8rpx;
    border: 2rpx solid #d4d6d9;

    .placeholder-text {
      @include setlightFont(28rpx, 36rpx, #bbbdbf);
    }

    ::v-deep {
      .uv-input {
        width: 100%;
        height: 100%;

        .uv-input__content__field-wrapper__field {
          &::placeholder {
            color: #bbbdbf !important;
            font-size: 28rpx;
            text-align: center;
          }
        }
      }
    }
  }
}
</style>

使用

 <selectPick v-model="product"
                    :columns="productList"
                    placeholder="姓名"></selectPick>

2.多选下拉款 级联框 需要peeg-tree 去插件市场导入

<template>
  <view>
    <view>
      <view style="width: 320rpx">
        <view class="item">
          <view class="content" @click="showTree">
            <uv-input :placeholder="`请选择${placeholder}`" disabled disabledColor="#ffffff" clearable border="none"
                     :value="modelValue?.name"
                     placeholder-style="color: #BBBDBF"></uv-input>
            <uv-icon name="arrow-right" color="#D4D6D9" size="32rpx"></uv-icon>
          </view>
        </view>
      </view>
    </view>
    <tki-tree
        ref="tkiTreeRef"
        :range="range"
        idKey="id"
        nameKey="name"
        allKey="value"
        :multiple="false"
        :cascade="false"
        :selectParent="true"
        :foldAll="false"
        confirmColor="#007aff"
        cancelColor="#757575"
        :title="'请选择部门'"
        titleColor="#757575"
        @cancel="treeCancel"
        @confirm="treeConfirm"
    >
    </tki-tree>
  </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import TkiTree from "../components/peng-tree/peng-tree.vue"
import {allChildList} from './api'

const props = defineProps({
  modelValue: {
    type: Object,
    default: null
  },
  placeholder: {
    type: String,
    default: '部门'
  },
  title: {
    type: String,
    default: '请选择'
  }
})

const emit = defineEmits(['update:modelValue'])

const tkiTreeRef = ref(null)
const range = ref([])

// 获取树形数据
const fetchTreeData =  () => {
  try {
    const obj = uni.getStorageSync('USER__INFO__');
    allChildList(obj.departmentId).then((res)=>{
      range.value = res.data
      emit('update:modelValue', range.value[0])
    })
  } catch (error) {
    console.error('获取部门数据失败:', error)
  }
}

const showTree = () => {
  const obj = uni.getStorageSync('USER__INFO__');
  if (obj.posts[0].code==='10005'){
    return
  }
  if (tkiTreeRef.value) {
    tkiTreeRef.value.showPick()
  }
}

const treeCancel = (e) => {
  console.log("取消选择", e)
}

const treeConfirm = (e) => {
  console.log("确认选择", e)
  if (e.length > 0) {
    emit('update:modelValue', e[0])
  }
}

onMounted(() => {
  fetchTreeData()
})
</script>
<style scoped lang="scss">
@import '/static/sass/global.scss';
.item {
  margin-bottom: 30rpx;
  .title {
    @include setBoldFont(28rpx, 36rpx, #000000);
    margin: 10px;
  }

  .content {
    margin-top: 20rpx;
    box-sizing: border-box;
    padding: 0 16rpx;
    height: 64rpx;
    width: 100%;
    display: flex;
    background: rgba(255, 255, 255, 0.8);
    border-radius: 8rpx 8rpx 8rpx 8rpx;
    border: 2rpx solid #d4d6d9;

    .placeholder-text {
      @include setlightFont(28rpx, 36rpx, #bbbdbf);
    }

    ::v-deep {
      .uv-input {
        width: 100%;
        height: 100%;

        .uv-input__content__field-wrapper__field {
          &::placeholder {
            color: #bbbdbf !important;
            font-size: 28rpx;
            text-align: center;
          }
        }
      }
    }
  }
}
</style>

使用

 <many-picker
            v-model="selectedDept"
            placeholder="部门"
            title="选择部门"
        />

3.图表

<template>
  <div class="chart-container">
    <qiun-data-charts
        type="line"
        :chartData="formatChartData"
        :opts="opts"
        :canvas2d="true"
    />
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

// 定义props
const props = defineProps({
  categories: {
    type: Array,
    default: () => []
  },
  series: {
    type: Array,
    default: () => []
  }
})

// 格式化图表数据
const formatChartData = computed(() => ({
  categories: props.categories,
  series: props.series
}))

// 图表配置
const opts = ref({
  color: ["#c099e5", "#FFAB41"],
  type:'area',
  padding: [15, 15, 0, 15],
  dataLabel: false,
  legend: {
    show: true,
    position:'top'
  },
  xAxis: {
    disableGrid: true,
  },
  yAxis: {
    gridType: 'dash',
    dashLength: 2,
  },
  extra: {
    area: {
      type: "curve",
      opacity: 0.4,
      addLine: true,
      width: 2,
      gradient: true,
      activeType: "hollow"
    }
  }
})
</script>

<style scoped>
.chart-container {
  width: 100%;
  height: 300px;
}
</style>

使用

  <line-chart :categories="xData" v-if="xData.length>0"
                      :series="yData"></line-chart>

4.科学计数法和百分数

// 字符串分割
export const toThousandFilter=(number)=> {
    // 如果number是字符串,尝试转换为数字
    if (typeof number === 'string') {
        number = parseFloat(number);
    }
    if (typeof number === 'number') {

        var parts = number.toFixed(2).toString().split('.'); // 分离整数部分和小数部分
        var integerPart = parts[0].split('').reverse(); // 反转整数部分
        var decimalPart = parts[1]; // 保留小数部分
        var tempNum = [];
        for (var i = 0; i < integerPart.length; i++) {
            tempNum.push(integerPart[i]);
            if ((i + 1) % 3 === 0 && i + 1 < integerPart.length) {
                tempNum.push(','); // 每三位添加一个逗号
            }
        }
        var formattedIntegerPart = tempNum.reverse().join(''); // 反转回来,得到正确的整数部分

        return formattedIntegerPart + '.' + decimalPart; // 合并整数和小数部分
    } else if (number !== undefined) {
        // WXS 中不支持 console.error,所以这里省略错误处理
        // 可以在 WXML 中使用 wx:if 来条件渲染或提示错误
    } else {
        return number;
    }

}
export const toRate=(numbera, numberb)=> {
    console.log(numbera, numberb)

    // 如果number是字符串,尝试转换为数字
    if (numbera === null) {
        return 0
    }
    // 如果number是字符串,尝试转换为数字
    if (typeof numbera === 'string') {
        numbera = parseFloat(numbera||0);
    }
    if (typeof numberb === 'string'|| numberb === null) {
        numberb = parseFloat(numberb||0);
    }
    console.log(numbera, numberb)
    if (numbera == 0) {
        if (numberb == 0) {
            return 0
        } else {
            return '100';
        }

    } else {
        let num=(numberb / numbera) * 100
        if(num===0){
            return 0
        }else{
            return num.toFixed(2);
        }
    }

}

### UniApp 的使用体验、优缺点及用户评价 #### 使用体验 UniApp 提供了一种跨平台开发解决方案,允许开发者利用 Vue.js 编写一次代码并部署至多个终端设备上。这种特性极大地提高了开发效率,减少了不同平台上维护多套代码的工作量[^1]。 然而,在实际操作过程中也存在一些挑战。由于其试图兼容多种环境,有时可能导致特定功能无法完美适配某些操作系统或硬件特性;另外,对于追求极致性能的应用来说,可能不是最佳选择,因为额外的抽象层可能会引入一定的开销。 #### 优点 - **高效开发**:借助于Vue.js的强大生态系统和支持组件化的架构模式,能够快速构建复杂界面。 - **广泛适用性**:支持iOS、Android、H5等多个主流平台的同时发布,极大降低了项目启动成本和技术门槛。 - **资源共享**:可以方便地重用现有的Web技术和工具链,如CSS预处理器、JavaScript库等,加速产品迭代周期。 #### 缺点 - **性能局限**:尽管大多数场景下表现良好,但在处理图形密集型任务或者需要高度优化交互效果的情况下,与其他原生方案相比可能存在差距。 - **社区规模较小**:相较于React Native 或 Flutter这样的竞争对手而言,UniApp背后的开源社区相对年轻,文档资料和第三方插件数量有限,这可能会影响解决问题的速度以及获取外部帮助的机会。 #### 用户反馈 关于用户体验方面,部分使用者反映虽然初期学习曲线较为平缓,但由于官方文档覆盖范围不够全面深入,遇到高级定制需求时会感到困难。此外,也有声音指出当涉及到更复杂的业务逻辑实现或是深度集成现有系统时,UniApp的表现不如预期那样理想。 ```python # 示例 Python 代码用于说明如何通过API调用来增强UniApp应用的功能 import requests def fetch_data_from_api(url): response = requests.get(url) if response.status_code == 200: return response.json() else: raise Exception('Failed to load data from API') ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

undefinedJJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值