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>
相关推荐
小雨cc5566ru10 小时前
uniapp+Android面向网络学习的时间管理工具软件 微信小程序
android·微信小程序·uni-app
二十雨辰15 小时前
[uni-app]小兔鲜-04推荐+分类+详情
前端·javascript·uni-app
小雨cc5566ru19 小时前
hbuilderx+uniapp+Android健身房管理系统 微信小程序z488g
android·微信小程序·uni-app
敲啊敲952719 小时前
uni-app之旅-day02-分类页面
前端·javascript·uni-app
二十雨辰20 小时前
[uni-app]小兔鲜-06地址+sku+购物车
前端·javascript·vue.js·uni-app
康康爹20 小时前
uniapp 小程序,登录上传头像昵称页面处理步骤
小程序·uni-app
小雨cc5566ru20 小时前
微信小程序hbuilderx+uniapp+Android 新农村综合风貌旅游展示平台
android·微信小程序·uni-app
小雨cc5566ru20 小时前
小程序 uniapp+Android+hbuilderx体育场地预约管理系统的设计与实现
android·小程序·uni-app
某公司摸鱼前端1 天前
uniapp 上了原生的 echarts 图表插件了 兼容性还行
前端·uni-app·echarts
貂蝉空大1 天前
uni-app 封装websocket 心跳检测,开箱即用
websocket·网络协议·uni-app