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>
相关推荐
小周同学:13 小时前
【UniApp打包鸿蒙APP全流程】如何配置并添加UniApp API所需的鸿蒙系统权限
华为·uni-app·harmonyos
初遇你时动了情1 天前
uniapp vue3 ts自定义底部 tabbar菜单
前端·javascript·uni-app
韩沛晓1 天前
uniapp跨域怎么解决
前端·javascript·uni-app
咸虾米2 天前
微信小程序服务端api签名,安全鉴权模式介绍,通过封装方法实现请求内容加密与签名
vue.js·微信小程序·uni-app
Ratten2 天前
使用 uniapp 实现的扫雷游戏
uni-app
YuShiYue2 天前
【uni-app】自定义导航栏以及状态栏,胶囊按钮位置信息的获取
uni-app·notepad++
2501_915921432 天前
iOS 应用上架多环境实战,Windows、Linux 与 Mac 的不同路径
android·ios·小程序·https·uni-app·iphone·webview
yede2 天前
uniapp - 自定义页面的tabBar
vue.js·uni-app
谢泽豪2 天前
解决 uniapp 修改index.html文件不生效的问题
前端·uni-app
00后程序员张2 天前
iOS 应用上架常见问题与解决方案,多工具组合的实战经验
android·ios·小程序·https·uni-app·iphone·webview