uni-app开发-组件封装通讯、计算属性与侦听器

一、组件封装通讯

1. 父传子(直接传,父组件引入并引用子组件,子组件通过props接收)

父组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <!-- 标签 小程序 -->
    <input type="text" placeholder="请输入内容" v-model="inputValue"><button @click="onConfirm">确定</button>
  </view>
  <view class="g-list">
    <view v-for="item in list" :key="item.id">
       <GoodsItem :goods="item"></GoodsItem>
    </view>
  </view>
</template>

<script setup>
import {ref} from 'vue'
import GoodsItem from '../../components/GoodsItem.vue'

const list = ref([
  {id:1001,name:'javascript高级编程',price:88.89,num:1},
  {id:1002,name:'vue高级编程',price:188.89,num:1},
])

const inputValue = ref('')

//确定
const onConfirm = ()=>{
  const good = {
    id:Math.floor(Math.random()*(9999-1000)+1000),
    name:inputValue.value,
    price:Math.floor(Math.random()*(999-100)+100),
    num:Math.floor(Math.random()*10)
  }
  
  list.value.push(good)
  inputValue.value = '' // 清除数据
}
</script>

<style scoped lang="scss">
.g-container{
  margin: 5px;
  display: flex;
  input{
    border: 1px solid gray;
    height: 40px;
    flex: 1;
  }

  button{
    width: 100px;
  }
}

</style>

根目录下创建一个components文件夹,文件夹中创建.vue文件,用于封装组件

子组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <image src="../static/logo.png" ></image>
    <view class="g-right">
      <text>ID: {{goods.id}}</text>
      <view class="">名称: {{goods.name}}</view>
      <view class="">价格: {{goods.price}}</view>
      <view class="">数量: {{goods.num}}</view>
    </view>
  </view>
</template>

<script setup>
   const props = defineProps(['goods'])

   // const props = defineProps({
   //   goods: Object,
   // })
</script>

 

<style scoped lang="scss">
.g-container{
  display: flex;
  image{
    width: 80px;
    height: 80px;
  }
  .g-right{
    flex: 1;
  }
}
</style>
2.子传父(父组件定义一个自定义事件,子组件接收并触发这个自定义事件,将参数传给父组件)

父组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <!-- 标签 小程序 -->
    <input type="text" placeholder="请输入内容" v-model="inputValue"><button @click="onConfirm">确定</button>
  </view>
  <view class="g-list">
    <view v-for="item in list" :key="item.id">
       <GoodsItem :goods="item" @binddelete="onDelete()"></GoodsItem>
    </view>
  </view>
</template>

<script setup>
import {ref} from 'vue'
import GoodsItem from '../../components/GoodsItem.vue'

const list = ref([
  {id:1001,name:'javascript高级编程',price:88.89,num:1},
  {id:1002,name:'vue高级编程',price:188.89,num:1},
])

const inputValue = ref('')

// 确定
const onConfirm = ()=>{
  const good = {
    id:Math.floor(Math.random()*(9999-1000)+1000),
    name:inputValue.value,
    price:Math.floor(Math.random()*(999-100)+100),
    num:Math.floor(Math.random()*10)
  }
  
  list.value.push(good)
  inputValue.value = '' // 清除数据
}

// 删除
const onDelete = (id)=>{
  const index = list.value.findIndex(item=>item.id===id)
  list.value.splice(index,1) //
}
</script>

<style scoped lang="scss">
.g-container{
  margin: 5px;
  display: flex;
  input{
    border: 1px solid gray;
    height: 40px;
    flex: 1;
  }
  
  button{
    width: 100px;
  }
}
</style>

子组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <image src="../static/logo.png" ></image>
    <view class="g-right">
      <text>ID: {{goods.id}}</text>
      <view class="">名称: {{goods.name}}</view>
      <view class="">价格: {{goods.price}}</view>
      <view class="">数量: {{goods.num}}</view>
      <button type="default" size="mini" @click="onDelete">删除</button>
    </view>
  </view>
</template>

<script setup>
   const props = defineProps(['goods'])
   
   // const props = defineProps({
   //   goods: Object,
   // })

   const emits = defineEmits(['binddelete'])

   // 删除
   const onDelete = ()=>{
     emits('binddelete', props.goods.id)
   }
</script>

<style scoped lang="scss">
.g-container{
  display: flex;
  image{
    width: 80px;
    height: 80px;
  }

  .g-right{
    flex: 1;
  }
}
</style>

二、计算属性与侦听器

1.计算属性computed

应用场景:

实现权限菜单

  1. 登录成功, 调用权限菜单接口获取菜单列表,保存到store

  2. 跳转到主界面,显示菜单列表

问题: 菜单列表获取是异步操作,如果没有保存store成功, 直接跳转到主界面,菜单不显示

解决办法: 1. store封装promise, 成功保存store返回后跳转

  1. 计算属性动态计算store菜单列表

下面是一个计算总价的小demo

父组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <!-- 标签 小程序 -->
    <input type="text" placeholder="请输入内容" v-model="inputValue"><button @click="onConfirm">确定</button>
  </view>
  <view class="g-list">
    <view v-for="item in list" :key="item.id">
       <GoodsItem :goods="item" @binddelete="onDelete()"></GoodsItem>
    </view>
  </view>
  <view class="g-totalprice">总价:{{totalPrice}}</view>
</template>

<script setup>
import {ref,computed} from 'vue'
import GoodsItem from '../../components/GoodsItem.vue'

const list = ref([
  {id:1001,name:'javascript高级编程',price:88.89,num:1},
  {id:1002,name:'vue高级编程',price:188.89,num:1},
])

const inputValue = ref('')

// 计算总价,累加
const totalPrice = computed(()=>{
  const total = list.value.reduce((prvious,current)=> prvious + current.price*current.num ,0)
  return total.toFixed(2)
})

// 确定
const onConfirm = ()=>{
  const good = {
    id:Math.floor(Math.random()*(9999-1000)+1000),
    name:inputValue.value,
    price:Math.floor(Math.random()*(999-100)+100),
    num:Math.floor(Math.random()*10)
  }
  
  list.value.push(good)
  inputValue.value = '' // 清除数据
}

// 删除
const onDelete = (id)=>{
  const index = list.value.findIndex(item=>item.id===id)
  list.value.splice(index,1) //
}
</script>

<style scoped lang="scss">
.g-container{
  margin: 5px;
  display: flex;
  input{
    border: 1px solid gray;
    height: 40px;
    flex: 1;
  }
  
  button{
    width: 100px;
  }
}
</style>

子组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <image src="../static/logo.png" ></image>
    <view class="g-right">
      <text>ID: {{goods.id}}</text>
      <view class="">名称: {{goods.name}}</view>
      <view class="">价格: {{goods.price}}</view>
      <view class="">数量: {{goods.num}}</view>
      <button type="default" size="mini" @click="onDelete">删除</button>
    </view>
  </view>
</template>

<script setup>
   const props = defineProps(['goods'])
   
   // const props = defineProps({
   //   goods: Object,
   // })

   const emits = defineEmits(['binddelete'])

   // 删除
   const onDelete = ()=>{
     emits('binddelete', props.goods.id)
   }
</script>

<style scoped lang="scss">
.g-container{
  display: flex;
  image{
    width: 80px;
    height: 80px;
  }

  .g-right{
    flex: 1;
  }
}
</style>
2.侦听器watch

应用场景:

搜索框(防抖与节流)

防抖: 触发高频事件时,n秒内再次触发,重新计算时间(只执行最后一次)

节流:触发高频事件时, n秒内再次触发,无效

根目录新建utils文件夹,utils文件夹中新建util.js文件,用于封装工具

kotlin 复制代码
/**

 * 手写防抖

 *   高频事件函数fun

 *   时间 n秒

 *

 *   返回防抖函数

 *   改变this指向

    call   apply  bind

 */

export const debounce = ( fun,n)=>{
  let timer = null
  return function(){
    clearTimeout(timer)
    timer = setTimeout(()=>{
      fun.apply(this)
    },n)
  }
}

父组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <!-- 标签 小程序 -->
    <input type="text" placeholder="请输入内容" v-model="inputValue"><button @click="onConfirm">确定</button>
  </view>
  <view class="g-list">
    <view v-for="item in list" :key="item.id">
       <GoodsItem :goods="item" @binddelete="onDelete()"></GoodsItem>
    </view>
  </view>
  <view class="g-totalprice">总价:{{totalPrice}}</view>
</template>

<script setup>
import {ref,computed,watch} from 'vue'
import GoodsItem from '../../components/GoodsItem.vue'
import { debounce } from '../../utils/util.js'

const list = ref([
  {id:1001,name:'javascript高级编程',price:88.89,num:1},
  {id:1002,name:'vue高级编程',price:188.89,num:1},
])

const inputValue = ref('')

// const bindInput = debounce(()=>{
// console.log('bindInput >>. ',inputValue.value);
// },500)

/**
 * 侦听器
 *  1. 响应式数据
 *  2. route  面包屑
 *  3. 立即侦听
 *  4. 深度侦听
 */

// 获取输入框内容,调用搜索接口获取列表数据,显示
// 问题: 每输入一个内容,都会触发侦听,调用接用,请优化一下
// 防抖: 触发高频事件时, n秒内再次触发,重新计算时间(只执行最后一次)
// 节流: 触发高频事件时, n秒内再次触发,无效

// 实现防抖
// watch(inputValue,(newValue)=>{
  // console.log('newValue >>>',newValue);
// })

watch(inputValue,debounce(()=>{
  console.log('bindInput >>. ',inputValue.value);
},500))

// 计算总价,累加
const totalPrice = computed(()=>{
  const total = list.value.reduce((prvious,current)=> prvious + current.price*current.num ,0)
  return total.toFixed(2)
})

// 确定
const onConfirm = ()=>{
  const good = {
    id:Math.floor(Math.random()*(9999-1000)+1000),
    name:inputValue.value,
    price:Math.floor(Math.random()*(999-100)+100),
    num:Math.floor(Math.random()*10)
  }
  
  list.value.push(good)
  inputValue.value = '' // 清除数据
}

// 删除
const onDelete = (id)=>{
  const index = list.value.findIndex(item=>item.id===id)
  list.value.splice(index,1) //
}
</script>

<style scoped lang="scss">
.g-container{
  margin: 5px;
  display: flex;
  input{
    border: 1px solid gray;
    height: 40px;
    flex: 1;
  }
  
  button{
    width: 100px;
  }
}
</style>

子组件.vue文件

xml 复制代码
<template>
  <view class="g-container">
    <image src="../static/logo.png" ></image>
    <view class="g-right">
      <text>ID: {{goods.id}}</text>
      <view class="">名称: {{goods.name}}</view>
      <view class="">价格: {{goods.price}}</view>
      <view class="">数量: {{goods.num}}</view>
      <button type="default" size="mini" @click="onDelete">删除</button>
    </view>
  </view>
</template>

<script setup>
   const props = defineProps(['goods'])
   
   // const props = defineProps({
   //   goods: Object,
   // })

   const emits = defineEmits(['binddelete'])

   // 删除
   const onDelete = ()=>{
     emits('binddelete', props.goods.id)
   }
</script>

<style scoped lang="scss">
.g-container{
  display: flex;
  image{
    width: 80px;
    height: 80px;
  }

  .g-right{
    flex: 1;
  }
}
</style>
相关推荐
小妖66615 小时前
uni-app 引入vconsole web端正常,安卓端报错 Cannot read property ‘sendBeacon‘ of undefined
android·前端·uni-app
源码宝16 小时前
ERP进销存系统源码,SaaS模式多租户ERP管理系统,SpringBoot、Vue、UniAPP技术框架
vue.js·spring boot·uni-app·源代码管理·erp·erp系统·进销存
七七小报17 小时前
uniapp-商城-43-shop 后台管理 页面
uni-app
牧杉-惊蛰17 小时前
uniapp 震动功能实现
uni-app
yrldjsbk1 天前
uniapp开发09-设置一个tabbar底部导航栏且配置icon图标
前端·uni-app
假客套1 天前
2025 后端自学UNIAPP【项目实战:旅游项目】1、创建项目框架
uni-app·旅游
济南壹软网络科技-专注源码开发数十年!1 天前
盲盒源码_盲盒系统_盲盒定制开发 盲盒搭建前端教程
开发语言·前端·uni-app·php
象骑士Hack1 天前
Uni-app小程序 hello world示例
小程序·uni-app
爱笑的眼睛112 天前
uniapp 云开发全集 云数据库
javascript·数据库·oracle·uni-app
青茶3602 天前
uniapp开发微信小程序时如何进行分包(新手图文)
微信小程序·小程序·uni-app