vue3封装一个基于element-plus的对话框-程序员宅基地

技术标签: dialog  vue  element-plus  vue3  

在vue3中自定义组件双向绑定语法的改变,使得写法和vue2大为不同。我们以element-plus的dialog组件为例。基于它。封装一个自己的对话框,同时介绍两种实现思路:

思路一:数据驱动型:

我们封装一个test-dialog组件:

<el-button @click="open">打开</el-button>

<test-dialog  ref="testDom"  v-model:visible="flag" ></test-dialog>

import TestDialog from "@/components/Dialogs/TestDialog"

import { reactive, toRefs, ref, onMounted, watch } from "vue"

setup() {

const state = reactive({

      flag: false

    })

 const open = () => {

      state.flag = true

    }

 watch(() => state.flag, (val) => {

      console.log("父组件监听flag:", val)

    })

}

子组件:

<template>

  <el-dialog

    title="提示"

    v-model="dialogVisble"

    width="30%"

    :before-close="close"

  >

    <span>这是一段信息</span>

    <template #footer>

      <span class="dialog-footer">

        <el-button @click="close">取 消</el-button>

        <el-button

          type="primary"

          @click="close"

        >确 定</el-button>

      </span>

    </template>

  </el-dialog>

</template>

<script>

import { ref, watch } from "vue"

export default {

  name: "TestDialog",

  components: {},

  props: {

    visible: {

      type: Boolean,

      default: false

    }

  },

  setup(props, ctx) {

    const dialogVisble = ref(false)

    const close = () => {

      ctx.emit("update:visible", false)

    }

    watch(() => dialogVisble.value, (val) => {

      ctx.emit("update:visible", val)

    })

    watch(() => props.visible, (val) => {

      dialogVisble.value = val

    })

    return {

      dialogVisble,

      open,

      close

    };

  },

};

</script>

<style scoped>

</style>

第二种思路:

类似直接操作dom,我们先通过ref拿到test-dialog组件的引用,每次点击打开按钮时,直接通过子组件去操作他内部的变量让它显示和隐藏

父页面:

<el-button @click="openByParentMethod ">打开</el-button>

<test-dialog  ref="testDom"  v-model:visible="flag" ></test-dialog>

import TestDialog from "@/components/Dialogs/TestDialog"

 setup() {

     const testDom = ref(null)

     const openByParentMethod = () => {

        testDom.value.dialogVisble = true

    }

    const closeByParentMethod= () => {

      testDom.value.dialogVisble = false

    }

   return {

      testDom,

      openByParentMethod,

     closeByParentMethod,

   }

}

子组件:

<template>

  <el-dialog

    title="提示"

    v-model="dialogVisble"

    width="30%"

    :before-close="close"

  >

    <span>这是一段信息</span>

    <template #footer>

      <span class="dialog-footer">

        <el-button @click="close">取 消</el-button>

        <el-button

          type="primary"

          @click="close"

        >确 定</el-button>

      </span>

    </template>

  </el-dialog>

</template>

 setup(props, ctx) {

    const dialogVisble = ref(false)

    const open = () => {

      dialogVisble.value = true

    }

    const close = () => {

      dialogVisble.value = false

    }

  return {

      dialogVisble,

      open,

      close

    };

  },

而对于vue2来说。实现这样的一个弹窗。则是通过如下方式:

 <select-city v-model="cityShow"></select-city>父组件通过v-model绑定变量cityShow,

而子组件中通过定义props:value,然后通过v-model 操控value来实现,如下:

1子组件在props中申明vaule,注意value名称是约定的不能写成其他的名称

2 子组件中通过 v-model="value"绑定改value

3关闭弹窗的时候,直接通过emit一个input事件来派发当前value的值。注意,这里只能写成input事件

(1)

 <van-action-sheet

      v-model="value"

    @close="close"

>

  内容xxx

</van-action-sheet>

export default {

  name: "selectCity",

  components: {},

  props: {

    value: {

      type: Boolean,

      default: false

    }

  },

 methods: {

    close() {

      console.log("close!!!!")

      this.$emit("input", this.cityShow)

    },

  },

针对vue2我们通过一个inputNm组件来具体看一看

<view class="item-menu-name">
			<view class="pt6 txtRt">
				{
   {item1.name}}
			</view>

			<view class=" pt6 vip-price txtRt">
				¥ {
   {item1.vipPrice}}会员价
			</view>
			<view class=" pt6 txtRt sale-price">
				¥ {
   {item1.salePrice}}
			</view>
			<view class="num-box">
				<InputNum v-model="item1.num" @increase="increseNum" @decresae="decreseNum"
									
			</view>
</view>
<script>

methods:{
    caculateTotal() {
		let total=0;
		this.tabbar.forEach(item => {
		item.foods.forEach(k => {
			console.log(" k.num", k.num)
						total += k.num
					})
		})
				this.total=total
				console.log("计算toatl",this.total)
		},
		increseNum() {
				this.caculateTotal()
		},
		decreseNum() {
				this.caculateTotal()

		},
		inputNum() {
				this.caculateTotal()

		},
}


</script>

没错InputNum 通过v-model绑定了我们购物车里的商品的数量。我们单独抽出这个组件进行计算

接下来我们看inputMum的具体实现

<template>
	<view class="inputnum-page">
		<view class="inputnum-container">
				<!-- <uni-transition :mode-class="fade" :show="num>0"> -->
					<view class="lt-container" v-if="curNum>0">
						<view class="oper-left-wrap">
							<view class="btn-left"  @click="decrease">
								-
							</view>
							<view class="oper-input">
								<input v-model="curNum" type="number"   class="ipt"/>
							</view>
						</view>
					</view>
				<!-- </uni-transition> -->
				<view class="rt-container">
					<view class="btn-right" @click="increase">
						+
					</view>
				</view>
		</view>
	</view>
</template>
<script>
	export default {
		props: {
			value: {
				type: Number,
				default: 0
			}
		},
		data() {
			return {
				maskClass: {
					opacity: 0,
				},
			}
		},
		computed:{
			curNum:{
				get(){
					return this.value
				},
				set(val){
					this.$emit("input", val);
				}
				
			}
			
		},

		methods: {
			decrease(){
				
				this.curNum--;
				if(this.curNum<=0){
					this.curNum=0;
					return 
				} 
				this.$emit("decrease",this.curNum)
			},
			
			increase(){
			
				this.curNum++;
				console.log("this.curNum",this.curNum)
				this.$emit("increase",this.curNum)
			}
		},
		mounted() {}
	}
</script>
<style scoped lang='scss'>
	.inputnum-page{
		margin-top: 10rpx;
	}
	.inputnum-container {
		width: 100%;
		display: flex;
	}
	.lt-container{
		width: 80%;
	}
	.rt-container{
		flex:1
	}
	.oper-left-wrap {
		width: 120rpx;
		display: flex;
		justify-content: flex-end;
	}
	.oper-input {
		width: 70rpx;
	}
	.btn-left,
	.btn-right {
		width: 40rpx;
		height: 40rpx;
		line-height: 40rpx;
		border-radius: 50%;
		background: #f00;
		color:#fff;
		display: flex;
		justify-content: center;
		align-items: center;
		font-size: 32rpx;
	}
	.ipt{text-align: center;}
</style>

props里为什么是value?对。这就是vue多v-model处理时的约定俗成。默认value和input事件就是v-model的语法糖。当然如果你想换成其他值,则需要单独配置model选项。

特别注意:这里computed的使用。如果我们不是通过computed来引用props的值而是单独把value作为inputNum;里v-model的绑定值。这样页面会报错Avoid mutating a prop directly since the value will be overwritten whenever...因为vue默认遵守单向数据流的思想。不允许子组件直接去更改父组件的props的值。而通过computed我们可以巧妙的绕开这个限制

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/baidu_41601048/article/details/117283634

智能推荐

基于Kepler.gl 和 Google Earth Engine 卫星数据创建拉伸多边形地图-程序员宅基地

文章浏览阅读965次,点赞18次,收藏21次。现在我们有了 2021 年和 2023 年的 NDVI 数据帧,我们需要从 2021 年的值中减去 2023 年的值以捕获 NDVI 的差异。该数据集包括像素级别的植被值,我们将编写一个自定义函数来根据红色和绿色波段的表面反射率计算 NDVI。在我的上一篇文章中,我演示了如何将单个多边形分割/镶嵌为一组大小均匀的六边形。现在我们有了植被损失数据,让我们使用 Kepler.gl 可视化每个六边形的植被损失。将地图保存为 HTML 文件,在浏览器中打开 HTML 以获得更好的视图。现在我们将调用该函数并使用、

Echarts绘制任意数据的正态分布图_echarts正态分布图-程序员宅基地

文章浏览阅读3.3k次,点赞6次,收藏5次。正态分布,又称高斯分布或钟形曲线,是统计学中最为重要和常用的分布之一。_echarts正态分布图

Android中发送短信等普通方法_android bundle.get("pdus");-程序员宅基地

文章浏览阅读217次。首先要在Mainfest.xml中加入所需要的权限:[html] view plain copyprint?uses-permission android:name="android.permission.SEND_SMS"/> uses-permission android:name="android.permission.READ_SMS"/> _android bundle.get("pdus");

2021-07-26 WSL2 的安装和联网_wsl2 联网-程序员宅基地

文章浏览阅读2.6k次。0、说明最近在学习 Data Assimilation Research Testbed (DART) 相关内容,其软件是在 Unix/Linux 操作系统下编译和运行的 ,由于我的电脑是 Windows 10 的,DART 推荐可以使用 Windows Subsystem For Linux (WSL) 来创建一个 Windows 下的 Linux 子系统。以下的内容主要介绍如何安装 WSL2,以及 WSL2 的联网。1、如何在 Windows 10 下安装WSL具体的安装流程可以在 microso_wsl2 联网

DATABASE_LINK 数据库连接_添加 database link重复的数据库链接命-程序员宅基地

文章浏览阅读1k次。DB_LINK 介绍在本机数据库orcl上创建了一个prod_link的publicdblink(使用远程主机的scott用户连接),则用sqlplus连接到本机数据库,执行select * from scott.emp@prod_link即可以将远程数据库上的scott用户下的emp表中的数据获取到。也可以在本地建一个同义词来指向scott.emp@prod_link,这样取值就方便多了..._添加 database link重复的数据库链接命

云-腾讯云-实时音视频:实时音视频(TRTC)-程序员宅基地

文章浏览阅读3.1k次。ylbtech-云-腾讯云-实时音视频:实时音视频(TRTC)支持跨终端、全平台之间互通,从零开始快速搭建实时音视频通信平台1.返回顶部 1、腾讯实时音视频(Tencent Real-Time Communication,TRTC)拥有QQ十几年来在音视频技术上的积累,致力于帮助企业快速搭建低成本、高品质音视频通讯能力的完整解决方案。..._腾讯实时音视频 分享链接

随便推点

用c语言写个日历表_农历库c语言-程序员宅基地

文章浏览阅读534次,点赞10次,收藏8次。编写一个完整的日历表需要处理许多细节,包括公历和农历之间的转换、节气、闰年等。运行程序后,会输出指定年份的日历表。注意,这个程序只是一个简单的示例,还有很多可以改进和扩展的地方,例如添加节气、节日等。_农历库c语言

FL Studio21.1.1.3750中文破解百度网盘下载地址含Crack补丁_fl studio 21 注册机-程序员宅基地

文章浏览阅读1w次,点赞28次,收藏27次。FL Studio21.1.1.3750中文破解版是最优秀、最繁荣的数字音频工作站 (DAW) 之一,日新月异。它是一款录音机和编辑器,可让您不惜一切代价制作精美的音乐作品并保存精彩的活动画廊。为方便用户,FL Studio 21提供三种不同的版本——Fruity 版、Producer 版和签名版。所有这些版本都是独一无二的,同样具有竞争力。用户可以根据自己的需要选择其中任何一种。FL Studio21.1.1.3750中文版可以说是一站式综合音乐制作单位,可以让您录制、作曲、混音和编辑音乐。_fl studio 21 注册机

冯.诺伊曼体系结构的计算机工作原理是,冯 诺依曼型计算机的工作原理是什么...-程序员宅基地

文章浏览阅读1.3k次。冯诺依曼计算机工作原理冯 诺依曼计算机工作原理的核心是 和 程序控制世界上不同型号的计算机,就其工作原理而言,一般都是认为冯 诺依曼提出了什么原理冯 诺依曼原理中,计算机硬件系统由那五大部分组成的 急急急急急急急急急急急急急急急急急急急急急急冯诺依曼结构计算机工作原理的核心冯诺依曼结构和现代计算机结构模型 转载重学计算机组成原理 一 冯 诺依曼体系结构从冯.诺依曼的存储程序工作原理及计算机的组成来..._简述冯诺依曼计算机结构及工作原理

四国军棋引擎开发(2)简单的事件驱动模型下棋-程序员宅基地

文章浏览阅读559次。这次在随机乱下的基础上加上了一些简单的处理,如进营、炸棋、吃子等功能,在和敌方棋子产生碰撞之后会获取敌方棋子大小的一些信息,目前采用的是事件驱动模型,当下完一步棋界面返回结果后会判断是否触发了相关事件,有事件发生则处理相关事件,没有事件发生则仍然是随机下棋。1.事件驱动模型首先定义一个各种事件的枚举变量,目前的事件有工兵吃子,摸暗棋,进营,明确吃子,炸棋。定义如下:enum MoveE..._军棋引擎

STL与泛型编程-第一周笔记-Geekband-程序员宅基地

文章浏览阅读85次。1, 模板观念与函数模板简单模板: template< typename T > T Function( T a, T b) {… }类模板: template struct Object{……….}; 函数模板 template< class T> inline T Function( T a, T b){……} 不可以使用不同型别的..._geekband 讲义

vb.net正则表达式html,VB.Net常用的正则表达式(实例)-程序员宅基地

文章浏览阅读158次。"^\d+$"  //非负整数(正整数 + 0)"^[0-9]*[1-9][0-9]*$"  //正整数"^((-\d+)|(0+))$"  //非正整数(负整数 + 0)"^-[0-9]*[1-9][0-9]*$"  //负整数"^-?\d+$"    //整数"^\d+(\.\d+)?$"  //非负浮点数(正浮点数 + 0)"^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0..._vb.net 正则表达式 取html中的herf