「注意,您的表单尚未填写完成」
好,我知道了。 (按下确定)
欸? 为什麽关不掉!?
不是按下确定就要关掉了吗?
这是谁做的烂东西啊,看我怎麽整死你!
(开发者人员工具打开後,兔兔惊呆。)
哦 ... 什麽嘛~原来是我之前的未完成品啊~ 其实也不是做得很烂啦! 只是那时候比较赶时间所以 ...
「兔兔,我们都听到罗~」
齁,不是这样的,就,呃 ... 好啦!
(咳咳!)
那看来今天的任务就是把它做完整,来雪耻了!!!
首先,在专案里的 ./src/components
资料夹中新增一个 Modal.vue
的元件:
然後:
<template>
</template>
<script>
export default {
name: "Modal",
}
</script>
为了成品的美观,修改一下 App.vue
内的样式,接着把元件新增到画面中:
<template>
<div :class="[
'w-screen h-screen',
'p-5'
]">
<Modal />
</div>
</template>
<script>
import Modal from './components/Modal.vue'
export default {
data() {
return {
}
},
components: {
Modal,
}
}
</script>
OK,下一步!
今天要参考的范本是 ...
有没有觉得很面熟啦~
没错,就是我们的 Creator!
今天要做出来的成品和 Creator 的 Modal 本身没有什麽差异哦~
首先,来分析一下要素:
主要类别就可以分成後面的覆盖层
,和前面的视窗
两类。 但视窗其实也还能再简易的切一下:
这样推理线索都具备後,就可以开始名侦探兔兔
的神还原了!
依据各个线索来推断,可以得到下面的结论:
半透明
和满版
!完全置中
於画面,压在覆盖层之上,然後 ... 那完美弧度,应该是传说中的小米定律
导致的
左、右
各有一个元素,看来是和手风琴选单相似
的犯罪手法「我应该没有漏说的吧?因为 ... 真相永远只有一个!」
当然 ... 因为前一次造下这犯行的人就是我自己啊 QQ
为了雪耻当然得更认真点!
来吧! 第一个先完成覆盖层和视窗的基底:
<div class="fixed top-0 left-0 w-screen h-screen p-5 flex justify-center items-center">
<!-- Modal-Overlay -->
<div class="absolute top-0 left-0 w-full h-full bg-black/50" />
<!-- Modal-Window -->
<div class="w-full max-w-sm bg-white rounded-md overflow-hidden z-10">
这是 Modal 视窗
</div>
</div>
对了,有注意到上面覆盖层的 bg-black/50
吗? 这就是之前在 Day 16 说过的便捷语法,快速就可以上完颜色和不透明度了。
还有,因为覆盖层的位置是 absolute
,所以会盖住视窗,记得加上 z-10
来调整 z 轴位置,把视窗的显示层级往上拉。
那上面都完成了,就可以准备来刻视窗内部了。
其实视窗的结构和 Day 27 的手风琴选单极为类似
,大部分东西都是一样的,而视窗内容区块的设计也与手风琴选单内容区的设计相同,移植
过来再修改一下
,就会像这样子:
<!-- Modal-Window -->
<div class="w-full max-w-sm bg-white rounded-md overflow-hidden z-10">
<div class="border-b-2 p-3 flex justify-between items-center">
<div class="font-bold text-gray-700">
注意
</div>
<div class="h-7 w-7 p-1 hover:bg-gray-200 active:scale-90 rounded-md cursor-pointer transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="h-full w-full" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</div>
</div>
<div>
<slot name="itemContent">
<div class="p-3">
<slot name="itemText">
这是 Modal 视窗
</slot>
</div>
</slot>
</div>
</div>
顺便把视窗标题的文字变成 Props
,这样们就可以从外部修改了:
<!-- 应用时 -->
<Modal title="嗨">
<template v-slot:itemText>
你好
</template>
</Modal>
完美至极!
接下来就要来完成我们最需要雪耻的 Modal 视窗开关部份了!
为了还要可以再度开启视窗,我们会用上 Day 26 做过的按钮哦~
我们就,开始吧!
首先,先来完成关闭的功能。 能够用来点击後关闭视窗的不外乎就是覆盖层和叉叉两处,但为了储存状态
,我们在 data 中要增加一个变数:
export default {
name: "Modal",
props: {
title: {
default: "注意"
}
},
data() {
return {
showed: true,
}
},
}
要先设为 true
哦!
不然等等一开始 Modal 就消失了 XD
然後写一个 methods 的函数 closing()
来处理关闭事件:
export default {
name: "Modal",
props: {
title: {
default: "注意"
}
},
data() {
return {
showed: true,
}
},
+ methods: {
+ closing() {
+ this.showed = false
+ }
+ }
}
然後把我们所写的函数应用上 template 中的覆盖层和叉叉,做为它们 onclick 事件
所触发的动作:
<div class="fixed top-0 left-0 w-screen h-screen p-5 flex justify-center items-center">
<!-- Modal-Overlay -->
<div
class="absolute top-0 left-0 w-full h-full bg-black/50"
@click="closing()"
/>
<!-- Modal-Window -->
<div class="w-full max-w-sm bg-white rounded-md overflow-hidden z-10">
<div class="border-b-2 p-3 flex justify-between items-center">
<div class="font-bold text-gray-700">
{{ title }}
</div>
<div
class="h-7 w-7 p-1 hover:bg-gray-200 active:scale-90 rounded-md cursor-pointer transition-all"
@click="closing()"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-full w-full" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</div>
</div>
<div>
<slot name="itemContent">
<div class="p-3">
<slot name="itemText">
这是 Modal 视窗
</slot>
</div>
</slot>
</div>
</div>
</div>
但现在按了仍然还不会有效果,因为我们还没有让 Modal 有相对应的样式变化。
不过因为兔兔的做法和外面一般的实现方法有些许不同,所以在这里先介绍一个会用到的特殊 CSS 属性: pointer-events
在 CSS 中,若想要让点击事件穿透到元素背後,使这个元素不会触发点击事件的话,pointer-events
就是你要找的功能。
在 Tailwind 中也有相对应的功能性 class,若要让点击穿透,就在该元素中使用 pointer-events-none
,若要恢复,则是 pointer-events-auto
。
所以在这里,兔兔决定若是不显示 Modal 时,Modal 整体会变成完全透明且可点击穿透
,显示 Modal 时则完全不透明且不可点击穿透
。我们用三元来实现:
<div
:class="[
'fixed top-0 left-0',
'w-screen h-screen',
'p-5',
'flex justify-center items-center',
'transition-all duration-300',
showed? 'opacity-100': 'opacity-0 pointer-events-none'
]"
>
<!-- Modal-Overlay -->
<div
class="absolute top-0 left-0 w-full h-full bg-black/50"
@click="closing()"
/>
<!-- Modal-Window -->
...
做到这里,去点击 Modal 的叉叉或覆盖层应该马上就有效果了,Modal 会淡出。
不过这样还不够华丽,我们顺便追加一下 Modal 视窗的动画。
Modal 视窗的部份我们让它在**不显示 Modal **时,会缩放到 0
;相反的,显示 Modal 时,缩放程度会回到 100
,也就是不缩放。这个我们也用三元运算子来做:
<!-- Modal-Window -->
<div
:class="[
'w-full max-w-sm bg-white rounded-md overflow-hidden z-10',
showed? 'scale-100': 'scale-0',
'transition-all duration-300'
]"
>
<div class="border-b-2 p-3 flex justify-between items-center">
<div class="font-bold text-gray-700">
{{ title }}
</div>
<div
class="h-7 w-7 p-1 hover:bg-gray-200 active:scale-90 rounded-md cursor-pointer transition-all"
@click="closing()"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-full w-full" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</div>
</div>
...
哈! 这样是不是很好看呢?
现在可以关起来了,可是却打不开 ...
不过也不用担心啦,把我们之前做的按钮拿出来用,让我们按下按钮来打开 Modal 吧!
但是要可以从外部开启,我们还必须在内部动一点手脚。
要可以从外部收取是否展开 Modal 的讯号,我们就要加上一个 Props 参数:
export default {
name: "Modal",
props: {
showModal: {},
title: {
default: "注意"
}
},
...
}
加好之後,别忘了做进度条时的事情,要监控外部
传来的变数内容来更新内部
的变数,还有在元件挂载时
也要做一次:
export default {
name: "Modal",
props: {
showModal: {},
title: {
default: "注意"
}
},
data() {
return {
showed: true,
}
},
mounted() {
this.showed = this.showModal
},
watch: {
showModal(newVal, oldVal) {
this.showed = newVal
}
},
methods: {
closing() {
this.showed = false
}
}
}
虽然这样看似完整了,不过还有一个小 bug。 我们在关闭事件 closing()
触发时一直都是改变内部的变数
,但外部的状态并不会被我们同步到
,所以我们必须用 emit
传递出去给父层:
methods: {
closing() {
this.showed = false
this.$emit("closing")
}
}
OK,这样 Modal 元件应该是完成罗!
接着来测试吧~
我们用之前做过的按钮快速来建立个测试环境。
我们必须现在 App.vue
中定义一个储存 Modal 开启状态的变数,按钮按下时会把变数变为 true,接收到来自 Modal 关闭事件触发时,会把变数设为 false。
那实作起来大概就是这样:
<template>
<div :class="[
'w-screen h-screen',
'p-5'
]">
<RabbitButton
class="w-40"
text="开启 Modal"
color="yellow"
@click="showed=true"
/>
<Modal
title="嗨"
:showModal="showed"
@closing="showed=false"
>
<template v-slot:itemText>
兔兔你好
</template>
</Modal>
</div>
</template>
<script>
import RabbitButton from './components/RabbitButton.vue'
import Modal from './components/Modal.vue'
export default {
data() {
return {
showed: true,
}
},
components: {
RabbitButton,
Modal,
}
}
</script>
OK~ 这样算是雪耻成功了吧?
还行吗? 会不会太难呢?
其实你应该会发现写久了,复杂度好像就那样而已,更多的是样式上的变化,还有怎麽做才会让自己未来可以更加的方便,其实人家说好的程序,是要能一直往上扩充,而不是去反覆修改原有的内容。
希望大家都能做顺利的自己造轮子嘿!
(如果开轮胎厂了,记得要让兔兔当股东。)
关於兔兔们:
( # 兔兔小声说 )
明天就是最後一天了呢~
说实在一路走来心里是很挣扎的,
因为根本就没想过可以坚持到这里,
而且,我这才发现自己在文章内容上的坑越挖越大了 XDDD加油!
>>: 【後转前要多久】# Day15 CSS -难东西 (伪元素)
项目清单分为条列式清(ol)单及编号清单(ul),两者的差别在於是否有自动排序项目的功能,<u...
上一篇我们的基因体时代-AI, Data和生物资讯 Day07- 蛋白质结构和机器学习02:Alph...
今天我们来实作第一个智能合约看看 首先,要发布智能合约一定就要就要有区块链,我们也不可能直接就真金白...
复习:渗透测试的目的 在合法委托下,确认目标网站或系统有可利用的漏洞,若确认有目标在取得授权下,提升...
Android 手机 行动电话 小人图示 talkback 无障碍按钮 导览列 捷径 协助工具按钮开...