五、指令(5)

本章概要

  • 实例
    • 通过指令实现下拉菜单
    • 使用自定义指令实现随机背景色

5.3 实例

5.3.1 通过指令实现下拉菜单

当鼠标移动到毛哥菜单上时会弹出一个子菜单列表,每个子菜单单项都是可以单击的,当鼠标移除整个菜单列表区域,子菜单列表隐藏。
此处按照菜单的层级关系,通过嵌套的 v-for 指令循环输出。
在 Vue 实例的数据属性中定义一个 menus 数组,将各个顶层菜单定义为一个对象,作为数组中的元素,子菜单作为顶层菜单对象的属性嵌套定义。如下:

data : {
  menus: [
    {
      name: '我的淘宝', url: '#', show: false, subMenus: [
          {name: '已买到的宝贝', url: '#'},
          {name: '已卖出的宝贝', url: '#'}
        ]
    },
    {
      name: '收藏夹', url: '#', show: false, subMenus: [
          {name: '收藏的宝贝', url: '#'},
          {name: '收藏的店铺', url: '#'}
        ]
    }
  ]
};

然后为每一个顶层菜单定义一个 show 属性,初始值为 false ,该属性主要用于控制其下的子菜单是否显示。
下拉菜单的子菜单初始是不显示的,只有当鼠标移动到顶层菜单时才会显示,当鼠标移动到菜单列表外边,子菜单列表要隐藏。这里定义的 show 属性就是用来标记这两种情况的,当需要显示时,将 show 设置为 true;当需要隐藏时,将 show 设置为 false。
接下来就该使用 v-for 指令循环输出菜单了。
对于这种有多个菜单的,采用 v-for 指令进行渲染时非常方便的,菜单可能有 二级菜单、三级菜单,这都没关系,无非就是使用多个 v-for 指令。
另外,子菜单的显示是鼠标移动到顶层菜单上,隐藏是鼠标移动到顶层菜单外部,因此还需要为所有的顶层菜单绑定两个鼠标事件:mouseover 和 mouseout。如下:

<div id = "app" v-cloak>
  <li v-for="menu in menus" @mouseover="menu.show = !menu.show" @mouseout="menu.show = !menu.show">
    <a :href="menu.url" >
      {{menu.name}}
    </a>
    <ul v-show="menu.show">
      <li v-for="subMenu in menu.subMenus">
        <a :href="subMenu.url">{{subMenu.name}}</a>
      </li>
    </ul>
  </li>
</div>

说明:

  • 在 div 元素中使用了 v-cloak 指令避免页面加载时的闪烁问题,当然,这需要和 CSS 样式规则 [v-cloak]{display:none} 一起使用。
  • 绑定 mouseover 和 mouseout 事件时采用了 v-on 指令的简写语法,menu.show 初始值为 false,因此 @mouseover 的表达式计算结果是将 menu.show 设为 true,而 @mouseout 表达式的计算结果是将 menu.show 设为 false。
  • 子菜单放在一个 ul 元素内部,在该元素上使用 v-show 指令,根据表达式 menu.show 的值动态控制子菜单的显示和隐藏。这里不适合使用 v-if 指令,因为子菜单的显示和隐藏可能会频繁切换。

本例主要的逻辑代码就是以上内容,剩下的主要是 CSS 样式的设置。完整代码如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			body {
				width: 600px;
			}
			a {
				text-decoration: none;
				display: block;
				color: #fff;
				width: 120px;
				height: 40px;
				line-height: 40px;
				border: 1px solid #fff;
				border-width: 1px 1px 0 0;
				background: #255f9e;
			}
			li {
				list-style-type: none;
			}
			#app > li {
				list-style-type: none;
				float: left;
				text-align: center;
				position: relative;
			}
			#app li a:hover {
				color: #fff;
				background: #ffb100;
			}
			#app li ul {
				position: absolute;
				left: -40px;
				top: 40px;
				margin-top: 1px;
				font-size: 12px;
			}
			[v-cloak] {
				display: none;
			}
		</style>
	</head>
	<body>
		<div id = "app" v-cloak>
			<li v-for="menu in menus" @mouseover="menu.show = !menu.show" @mouseout="menu.show = !menu.show">
				<a :href="menu.url" >
					{{menu.name}}
				</a>
				<ul v-show="menu.show">
					<li v-for="subMenu in menu.subMenus">
						<a :href="subMenu.url">{{subMenu.name}}</a>
					</li>
				</ul>
			</li>
		</div>
	
		<script src="https://unpkg.com/vue@next"></script>
		<script>
		    const data = {
		      menus: [
		      	{
		      		name: '我的淘宝', url: '#', show: false, subMenus: [
		      				{name: '已买到的宝贝', url: '#'},
		      				{name: '已卖出的宝贝', url: '#'}
		      			]
		      	},
		      	{
		      		name: '收藏夹', url: '#', show: false, subMenus: [
		      				{name: '收藏的宝贝', url: '#'},
		      				{name: '收藏的店铺', url: '#'}
		      			]
		      	}
		      ]
		    };
		    const vm = Vue.createApp({
                data() {
                    return data;
                }
            }).mount('#app');
		</script>
	</body>
</html>

运行结果如下:
在这里插入图片描述

5.3.2 使用自定义指令实现随机背景色

有时候会使用一张图作为网页中某个元素的背景图,当网络状况不好时,或者图片本身较大时,图片的加载会比较慢。
在这种情况下,可以先在该元素的区域用随机的背景色填充,等图片加载完成后,再把元素背景替换为图片。如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		
		<style>
			div{
				width: 567px; 
				height: 567px;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<div v-img="'images/bg.jpg'"></div>
		</div>
	
		<script src="https://unpkg.com/vue@next"></script>
		<script>
		    const app = Vue.createApp({});
			app.directive('img', {
				mounted: function(el, binding){
					let color = Math.floor(Math.random() * 1000000);
					el.style.backgroundColor = '#' + color;
					let img = new Image();
					img.src = binding.value;
					img.onload = function(){
						el.style.backgroundImage = 'url(' + binding.value + ')';
					}
				}
			})
			app.mount('#app');
		</script>
	</body>
</html>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小熊猫呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值