jQuery超详细总结
文章目录
jQuery超详细总结
一 选择器
特殊选择器
二 筛选器
用在 jQuery 选择的元素后面
都是方法,对选择出来的元素进行二次筛选
三 文本操作
总结
四 元素类名操作
五 元素属性操作
在 H5 的标准下, 给了一个定义, 当你需要写自定义属性的时候,最好写成 data-xxx="值",当大家看到 data-xxx 的时候, 就知道这是一个自定义属性
六 元素样式操作
七 绑定事件
on()方法是专门用来绑定事件one() 方法是专门用来绑定一个只能执行一次的方法off() 方法是专门用来解绑一个元素的事件的trigger() 方法是专门用来触发事件的方法hover()常用事件offset()position()scrollTop()scrollLeft()ready() 事件each() 方法jQuery 发送一个 GET 请求jQuery 发送一个 POST 请求jQuery 的 $.ajax 方法position()
postition: 定位
只读的方法
读取:
元素相对于定位父级的位置关系
得到的也是一个对象 { left: xxx, top: xxx }
如果你写的是 right 或者 bottom, 会自动计算成 left 和 top 值给你
十一 获取卷去的尺寸(页面滚动条)
scrollTop()
原生 js 里面 document.documentElement.scrollTop
读写的方法
不传递参数的时候就是获取卷去的高度
传递一个参数就是设置卷去的高度
scrollLeft()
原生 js 里面 document.documentElement.scrollLeft
读写的方法
不传递参数的时候就是获取卷去的宽度
传递一个参数的时候就是设置卷去的宽度
十二 jQuery中的函数
ready() 事件
类似于 window.onload 事件,但是有所不同
window.onload 会在页面所有资源加载行
ready() 会在页面 html 结构加载完毕后执行
也叫做 jQuery 的入口函数
有一个简写的形式 $(function () {})
each() 方法
类似于 forEach(), 遍历数组的
jQuery 的元素集合, 是一个 jQuery 数组, 不是一个数组, 不能使用 forEach()
forEach语法: forEach(function (item, index) {})
each语法:each(function (index, item) {})
比较少用到, 因为 jQuery 隐式迭代 自动遍历
十三 jQuery中的动画
让元素出现不同的移动, 改变
transition -> 过渡动画
animation -> 帧动画
标准动画
show() 显示元素
语法: show(时间, 运动曲线, 运动结束的函数)
hide() 隐藏元素
语法: hide(时间, 运动曲线, 运动结束的函数)
toggle() 改变元素显示或隐藏(如果显示就隐藏,如果隐藏就显示)
语法: toggle(时间, 运动曲线, 运动结束的函数)
三个方法的参数都可以选填,不需要每个都填写
折叠动画
slideDown() 下滑显示
语法: slideDown(时间, 运动曲线, 运动结束的函数)
slideUp() 上滑隐藏
语法: slideUp(时间, 运动曲线, 运动结束的函数)
slideToggle() 切换滑动和隐藏
语法: slideToggle(时间, 运动曲线, 运动结束的函数)
渐隐渐显动画
实质是透明的opacity的变化
fadeIn() 逐渐显示
fadeIn(时间, 运动曲线, 运动结束的函数)
fadeOut() 逐渐消失
fadeOut(时间, 运动曲线, 运动结束的函数)
fadeToggle() 切换显示和消失
fadeToggle(时间, 运动曲线, 运动结束的函数)
以上三个方法的参数,均有默认值
fadeTo() 设置元素透明度变为你指定的数字
fadeTo(时间, 你指定的透明度, 运动曲线, 运动结束的函数)
综合动画
animate()
基本上大部分的 css 样式都可以动画
transform 不行, 颜色不行
语法: animate({}, 时间, 运动曲线, 运动结束的函数)
{ }里面就写你要运动的 css 属性,默认单位为px
停止动画
让当前的动画结束
因为 jQuery 的动画你一直点击,就会一直触发。即使不再点击让事件发生,还是会把没执行完的动画执行完毕。
你点击 10 次, 他就会触发 10 次, 直到 10 次全都完毕才结束
stop()
当这个函数触发的时候, 就会让运动立刻停下来
你运动到哪一个位置了就停止在哪一个位置
finish()
当这个函数触发的时候, 就会让运动立刻停下来
不管你运动到了哪一个位置, 瞬间到达运动完成位置
十四 jQuery发送ajax请求
jQuery 里面帮我们封装好了几个方法
专门用来发送 ajax 请求的
$.get() -> 专门用来发送 get 请求的
$.post() -> 专门用来发送 post 请求的
$.ajax() ->
发送什么请求都可以(get, post, put, delete)
并且还可以发送一个 jsonp 请求
jQuery 发送一个 GET 请求
语法: $.get(请求地址, 需要携带到后端的参数, 成功的回调函数, 期望后端返回的数据类型)
请求地址: 你要请求的后端接口地址(必填)
携带参数: 你需要给后端传递的参数
可以是一个固定格式的字符串 ‘key=value&key=value’
也可以是一个对象 { a: 100, b: 200 }
成功回调: 当请求成功的时候会执行的函数
期望数据类型: 就是你是不是需要 jQuery 帮你解析响应体
$.ajax({
url: '', // => 请求地址(必填)
type: '', // => 请求方式(GET, POST, ...) 默认是 GET
data: '', // => 携带到后端的参数
dataType: '', // => 期望后端返回的数据类型, 默认不解析
async: true, // => 是否异步, 默认是 true
success: function () {}, // => 成功的回调
error: function () {}, // => 失败的回调
timeout: 数字, // 单位是 ms, 超时时间(超过你写的时间没有响应, 那么就算失败)
cache: true, // 是否缓存, 默认是 true
context: 上下文, // 改变回调函数里面的 this 指向
...
})
$.ajax 里面失败的回调
不光是请求失败的时候会触发
jQuery 认定失败就是失败
当 dataType 写成 json 的时候, jQuery 会帮我们执行 JSON.parse()
当后端返回一个不是 json 格式的字符串的时候
执行 JSON.parse() 就会报错
也会执行失败的回调, 请求虽然成功, 但是解析失败了, 也是失败
JSON.parse(‘你好 世界’) -> 就会报错了
$.ajax 里面是否缓存的问题
这个请求要不要缓存
当两次请求地址一样的时候, 就会缓存
如果你写成 false, 表示不要缓存
jQuery 就会自动再你的请求后面加一个参数 =时间戳
第一次请求 ./server/get.php?=11:10:01.325的时间戳
第二次请求 ./server/get.php?_=11:10:02.326的时间戳
$.ajax 里面的回调 this 指向问题
ajax 的回调里面默认 this 指向被 jQuery 加工过的 ajax 对象
context 的值你写的是谁, 回调函数里面的 this 就时谁
$.ajax 里面的请求方式的问题
$.ajax 这个方法里面, type 表示请求方式
jQuery 还给了我们一个参数叫做 method,也表示请求方式
当你写请求方式的时候
可以写成 type: ‘POST’
也可以写成 method: ‘POST’
$.ajax 里面的接收响应的问题(2015年以后的版本才有 promise 的形式)
jQuery 默认把 ajax 封装成了 promsie 的形式
你可以用 success 选项接收成功的回调
也可以用 .then() 的方式接收响应
jQuery 的 ajax 全局钩子函数
钩子: 挂在你的身上, 你的所有动作都和它有关系
这些全局函数都是挂在 ajax 身上的, 这个 ajax 的每一个动作都和全局函数有关系
全局的钩子函数
1.ajaxStart()
会在同一个作用域下多个 ajax 的时候, 第一个 ajax 之前开始的时候触发
如果有多个 ajax 他只触发一次
2.ajaxSend()
每一个 ajax 再发送出去之前, 都会触发一下
xhr.send() 之前触发
ajaxSuccess()
每一个 ajax 再成功的时候触发
只要有一个 ajax 成功了就会触发
ajaxError()
每一个 ajax 再失败的时候触发
只要有一个 ajax 失败了就会触发
ajaxComplete()
每一个 ajax 完成的时候触发
只要有一个 ajax 完成了, 不管成功还是失败, 都会触发
ajaxStop()
会在同一个作用域内多个 ajax 的时候, 最后一个 ajax 完成以后触发
如果有多个 ajax 它只触发一次
作用: 通常用来做 loading 效果
<img src="./loading.gif" alt="">
// 利用ajax钩子函数 做一个lading效果 等待页面
// 提前利用钩子函数准备 loading 效果
// 每一次发送出去的时候都要显示图片
$(window).ajaxSend(() => {
$('img').show()
})
// 每一次完成的时候都要图片再隐藏起来
$(window).ajaxComplete(() => {
$('img').hide()
})
// 每次点击按钮的时候都会发送一个 ajax 请求
$('button').click(() => {
// 发送一个 ajax 请求
$.ajax({
url: './server/get.php',
data: { a: 100, b: 200 },
dataType: 'json',
success: function (res) {
console.log('请求成功了')
console.log(res)
}
})
})
十五 jQuery 发送一个 jsonp 请求
jQuery 也提供给我们发送 jsonp 请求的方式
jsonp: 利用 script 标签的 src 属性来请求
返回值: 是一个字符串, 字符串里面写了一个 函数名(后端传递给前端的参数)
使用 $.ajax() 这个方法
必须写的:dataType: 'jsonp'
发送 jsonp 请求
jQuery 帮我们准备好了一个函数名, 并且以参数的形式带到了后端
jQuery 帮我们带过去的 callback 参数, 就是它准备好的函数名
后端就应该返回一个 jQuery 准备好的函数名()
其他参数
jsonp: '', 你带到后端表示你函数名的那个 key, 默认值是 callback
cache: false, 当 dataType === ‘jsonp’ 的时候, 默认 cache 就是 false
// 发送一个 jsonp 请求
$.ajax({
url: 'http://127.0.0.1/server/jsonp.php',
dataType: 'jsonp', // 表示我要发送一个 jsonp 请求
jsonp: 'cb', // 表示参数里面的 cb 属性时我准备好的函数名
cache: true, // 表示缓存本次请求
success: function (res) {
console.log(res)
}
})
// jQuery 准备好的函数名
// + jQuery34108160883644340862_1582255906750
// + 变量名包含 数字 字母 下划线 $
// + function jQuery34108160883644340862_1582255906750() {}
十六 jQuery 的多库并存机制
因为 jQuery 引入页面以后, 向全局添加了两个名字
一个叫做 $
一个叫做 jQuery
万一有别的类库也起名叫做 jQuery 或者$ 怎么办
当我两个库都需要使用的时候
因为向全局暴露的名字一样, 就会发生冲突了
谁的文件引再后面, 谁的名字就占主要位置了
两个只能选择一个使用
jQuery 提供了一个方法
我可以不占用$ 或者 jQuery 这个名字
noConflict()
语法: $.noConflict() 或者jQuery.noConflict()
当你执行了 noConflict() 以后, jQuery 就交出了$的控制权。
jQuery向全局暴露的不在有$ 这个名字了。当你执行了noConflict(true) 以后, jQuery就交出了 $ 和jQuery 的控制权。
交出去以后, 我的 jQuery 就用不了
noConflict() 的返回值: 就是一个新的控制权
你只要接收一个返回值, 你定好的变量是什么,jQuery 的控制权就是什么
// 交出 $ 的控制权
// $.noConflict()
// 交出 $ 和 jQuery 的控制权
// $.noConflict(true)
// 改变 jQuery 的控制权
var $$ = $.noConflict(true)
十七 jQuery 的插件扩展机制
jQuery 还提供给我们了一个机制, 就是你可以向 jQuery 里面扩展一些方法
两个方法
$.extend()
扩展给 jQuery本身使用的
语法:
$.extend({ 你要扩展的方法名: function () {}, 你要扩展的方法名: function () {}, ... })
使用的时候就是 $.你扩展的方法名()
$.fn.extend() => $.extend($.fn, { 你扩展的方面名 })
扩展给 jQuery 元素集合使用的
语法 $.fn.extend({ 你要扩展的方法名: function () {}, 你要扩展的方法名: function () {}, ... })
使用的时候就是 $(选择器).你扩展的方法名()
$('div').html()
// 1. 扩展给 jQuery 本身
// jQuery 本身没有操作 cookie 的方法
// $.extend({
// setCookie: function (key, value, expires) {
// // 写上设置 cookie 的方法
// if (expires) {
// var time = new Date()
// time.setTime(time.getTime() - 1000 60 60 8 + 1000 expires)
// document.cookie = ${key}=${value};expires=${time}
// } else {
// document.cookie = ${key}=${value}
// }
// },
// getCookie: function (key) {
// // ...
// }
// })
// 使用我们扩展的方法去设置 cookie
// $.setCookie('a', 100)
// $.setCookie('b', 200, 10)
// 2. 扩展给元素集合
// 扩展一个全选的方法
// 方法以执行, 就能让 input checkbox 变成选中状态或者不选中状态
$.fn.extend({
selectAll: function (type = true) {
// type 就是你传递进来的选中或者不选中一个标志
// 你不传递的时候, 我默认是 true, 你传递了就用你传递的
// console.log(this) // 就是你调用的时候前面的哪个元素集合
this.each(function (index, item) {
// 让元素集合中的每一个 input 的 checked 属性为 true
item.checked = type
})
// return 这个元素集合, 达到一个链式编程的效果
return this
}
})
$('button').click(() => {
// 让所有 input 框变成选中状态
console.log($('input').selectAll().attr('hello', 'world'))
})
十八 jQuery 的拷贝对象问题
$.extend() 深拷贝 与 浅拷贝
传递一个对象的时候, 可以做到插件扩展机制
传递多个对象的时候, 可以将后面几个对象的内容复制到第一个对象里面
语法:
$.extend(是否深拷贝, 对象1, 对象2, 对象3, ...)
是否深拷贝: 默认是 false, 可以不写
从 对象2 开始, 后面所有对象的内容都会被拷贝到 对象1 里面
再拷贝的时候, 如果有重复的 key, 那么以写在后面的为准(后来者居上)
十九 jQuery 的插件
基于 jQuery 使用的, 别人封装好的插件
我们拿来使用就可以了, 前提就是要有 jQuery
例子 一个叫做 jquery-validate 的插件
专门用来做表单验证的
你输入的内容是不是符合规则
下载
引入文件
去复制粘贴
<!-- 引入文件 --> <!-- 注意: 先引入 jQuery, 后引入 jquery-validate --> <script src="./jquery/jquery.min.js"></script> <!-- jquery-validate 这个文件依赖的 jquery --> <script src="./jquery-validate/jquery.validate.min.js"></script> <!-- 引入中文信息提示包, 必须在 jquery-validate 的后面 --> <script src="./jquery-validate/localization/messages_zh.min.js"></script> <script>
// 选择到你要验证的表单的 form 标签
// 执行 validate 方法
// {} 里面就写我们的验证规则
$('#login').validate({
// 你需要的验证规则
rules: {
// key 就是你要验证的哪个 input 框的 name 属性
username: 'required', // 用户名必填
password: { // 一个字段可以写多个验证方式
required: true,
minlength: 6, // 最少是六个
maxlength: 12, // 最多十二个
}
},
// 你自定义提示的文本内容
messages: {
// key 就是你验证的哪个 input 框的 name 属性
username: '请输入用户名! ^_^',
password: {
required: '请输入密码!',
minlength: '最少要输入 6 个字符噢!'
}
},
// 表单的提交事件
// 这个函数会在表单验证通过以后执行
submitHandler: function (form) {
// form 接收的就是你的 form 标签
// console.log(form)
// console.log('表单验证通过了, 我需要使用 ajax 去提交数据了')
// 有一个 jQuery 的方法
// serialize() 快速获取表单输入的数据
// $(form).serialize() 就能拿到这个 form 标签里面的表单数据
// console.log($(form).serialize()) // username=admin&password=123456
// 发送请求到后端
$.post('./server/login.php', $(form).serialize(), res => {
console.log(res)
}, 'json')
}
})
————————————————1.文字滚动
<html>
<head>
<title>我的第一个页面</title>
</head>
<body>
<marquee behavior="scroll" direction="up" height="30" style="overflow:hidden;" scrollamount="1" width="300" onMouseOver="stop()" onMouseOut="start()">
雷电黄色预警!<br />
大雨黄色预警!<br />
</marquee>
</body>
</html>
direction:方向
up:上 down:下 left:左 right:右
scrollamount:滚动速度-----------------scroll:滚动 amount:数值
width:宽度 height:高度
onmouseover:当鼠标移上去
onmouseout:当鼠标离开
stop():停止
start():开始
behavior:
scroll 循环滚动
alternate 来回滚动
slide 滚动一次停止
一.有关于内置对象的作用域
主要说明2个对象,request,session
1、request 对象
request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。
request只在2个页面之间传递,每一次新的请求都会新建一个request对象,也就是说可能会request对象不一致导致空指针异常。
2、session 对象
session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。
session对象在整个会话只有一个,也就是说session对象的数据会一直保留直到主动进行数据更改。
二.表单提交
在index.jsp中使用form进行数据的提交,action的目标是check.jsp,method是post
三.验证跳转
当form提交信息后交给check.jsp验证,使用getParameter来得到form的信息,并使用setAttribute保存。在check.jsp中判断账号密码是否正确后,使用
<jsp:forward page=".jsp"></jsp:forward>
1
进行跳转,.jsp是想要跳转的页面路径。
四.详细代码
index.jsp
<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>登陆</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form action="check.jsp" method="post">
请输入用户名:
<input type = "text" name = "username"><br/>
请输入密码:
<input type = "password" name = "passwd"><br/>
<input type="submit" name="submit" value="登录">
</form>
</body>
</html>
check.jsp
<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>验证</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<%
String username = (String)request.getParameter("username");
String passwd = (String)request.getParameter("passwd");
request.setAttribute("username", username);
request.setAttribute("passwd", passwd);
if(username.equals("admin")&&passwd.equals("123")){
%>
<jsp:forward page="succeed.jsp"></jsp:forward>
<%}else{ %>
<jsp:forward page="failed.jsp"></jsp:forward>
<%} %>
</body>
</html>
succeed.jsp
<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>登陆成功</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<%
String username = (String)request.getAttribute("username");
String passwd = (String)request.getAttribute("passwd");
%>
<%=username %>登陆成功
</body>
</html>
failed.jsp
<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>登陆失败</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<%
String username = (String)request.getAttribute("username");
String passwd = (String)request.getAttribute("passwd");
%>
<%=username %>登陆失败
</body>
</html>
五.注意事项
在jsp中使用form提交表单不能直接进行跳转,否则操作不慎就容易出现空指针异常,建议交由单独的跳转页面处理
下面这段代码是实现简单的导航效果:
在这里插入代码片<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
*{
margin:0px;
padding:0px;
list-style:none;
}
.nav{
width:700px;
margin:100px auto;
}
.nav ul li{
float:left;
margin-right:5px;
}
.nav ul li a{
width:100px;
height:30px;
color:#fff;
display:block;
line-height:30px;
margin-right:5px;
text-decoration:none;
background:red;
text-align:center;
}
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.nav ul li a:hover{
background:yellow;
color:blue;
text-decoration:underline;
}
</style>
</head>
<body>
<div class="nav">
<ul class="clearfix">
<li><a href="#">导航</a></li>
<li><a href="#">导航</a></li>
<li><a href="#">导航</a></li>
<li><a href="#">导航</a></li>
<li><a href="#">导航</a></li>
</ul>
</div>
</body>
</html>
实现效果如图:
容易犯错的地方:刚开始我把display:block;属性写在最前面,结果一直出不来,后来发现display属性应该放在height和width属性后面
我还学到一个知识点:关于父元素塌陷问题:
在文档流中,父元素的高度默认是被子元素撑开的,也就是说父元素多高,子元素就多高
但是为子元素设置浮动以后,子元素就会完全脱离文档流,此时将会导致子元素无法撑起父元素的高度,导致父元素的高度塌陷
由于父元素的高速塌陷了,则父元素下所有的元素都会向上移动,这样会导致页面布局混乱
所以我们在开发中一定要避免出席那高度塌陷的问题,这时候我们可以将父元素的高度写死,这样可避免塌陷的问题出现,但是一当高度写死,父元素的高度将不能自动适应子元素的高度,所以这种方式是不推荐使用的
1
解决的方案:
根据W3C标准,在页面中元素有一个隐含的属性叫做Block Formatting Context
方案一:*(设置zoom为1和overflow为hidden)
当开启元素的BFC后,元素会有以下特性:
父元素的垂直外边距不会和子元素重叠
开启BFC的元素不会被浮动元素所覆盖
开启BFC的元素可以包含浮动的子元素
那如何开启元素的BFC呢?
设置元素浮动
设置元素的绝对定位
设置元素为inline-block(但是设置inline-block可以解决问题,但是会导致宽度丢失,所以不推荐使用这种方式)
将元素的overflow设置为一个非visible的值(推荐方式:将overflow:hidden这个是副作用最小的开启BFC方式,所以可以这么说,以后若是再塌陷,就给父元素加上overflow:hidden属性)
但需要注意的是:
在IE6以及以下的浏览器中并不支持BFC,所以使用这种方式并不能兼容IE6,在IE6中虽然没有BFC,但有另一个隐藏属性叫做hasLayout该属性作用和和BFC类似。但在IE6浏览器可以通过开hasLayout来解决问题
开启方式很多,我们可以直接用一种副作用最小的直接将元素的zoom设置为1,比如父元素是box1,我们可以在父元素中加上zoom:1;
在这里解释一下zoom表示放大的意思,后边跟着一个数值,写几就可以将元素放大几倍,所以zoom:1表示不放大元素,但是可以通过该样式可以开启hasLayout.
但需要注意的是zoom属性放IE6可以,别的浏览器比如Chrome就不行
****所以重头戏来了:若我们想要兼容所有浏览器?
1.引入
三种引用方式
第一种 npm安装
项目根目录命令行执行
npm install uni-simple-router
1
第二种 插件市场(使用HBuilderX导入插件)
第三种 ZIP下载 解压
2.项目中引入
import Vue from 'vue'
import {RouterMount} from 'uni-simple-router';
import Router from './router'
Vue.use(Router)
//...后续代码
引入之后就开始我们的正式使用。
第一步先在项目的根目录下创建一个router文件夹。
格式为:
router
|---modules
|---index.js
|---index.js
router中的modules文件夹是用来放路由表模板的。modules中的index.js内容为
const files = require.context('.', false, /.js$/)
const modules = []
files.keys().forEach(key => {
if (key === './index.js') return
const item = files(key).default
modules.push(...item)
})
export default modules
这个文件用来把同目录下的js文件读取并整合所有路由。
在这里创建的js文件代码示例:
const home = [
{
//注意:path必须跟pages.json中的地址对应,最前面别忘了加'/'哦
path: '/pages/home/index',
aliasPath:'/', //对于h5端你必须在首页加上aliasPath并设置为/
name: 'index',
meta: {
title: '首页',
},
},
{
path: '/pages/home/list',
name: 'list',
meta: {
title: '列表',
},
},
]
export default home
第二步配置router下的index.js
import modules from './modules'
import Vue from 'vue'
//这里仅示范npm安装方式的引入,其它方式引入请看最上面【安装】部分
import Router from 'uni-simple-router'
Vue.use(Router)
//初始化
const router = new Router({
routes: [...modules]//路由表
});
//全局路由前置守卫
router.beforeEach((to, from, next) => {
next()
})
// 全局路由后置守卫
router.afterEach((to, from) => {
})
export default router;
第三步 就是配置main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import { RouterMount } from 'uni-simple-router'
App.mpType = 'app'
const app = new Vue({
...App
})
//v1.3.5起 H5端 你应该去除原有的app.$mount();使用路由自带的渲染方式
// #ifdef H5
RouterMount(app,'#app');
// #endif
// #ifndef H5
app.$mount(); //为了兼容小程序及app端必须这样写才有效果
// #endif
这样你的路由就配置好了。
如果不想繁琐的配置modules下的文件,可以用webpack自动构建路由表
安装
npm install uni-read-pages
1
配置 vue.config.js (可能需要手动创建)
const TransformPages = require('uni-read-pages')
const tfPages = new TransformPages({
//如果你需要获取更多参数,那么请配置参数!
includes:['path','name','meta']
})
module.exports = {
configureWebpack: {
plugins: [
new tfPages.webpack.DefinePlugin({
ROUTES: JSON.stringify(tfPages.routes)
})
]
}
}
然后去pages.json里面更改配置,加入所需要的内容
最后配置路由表
import Vue from 'vue'
//这里仅示范npm安装方式的引入,其它方式引入请看最上面【安装】部分
import Router from 'uni-simple-router'
Vue.use(Router)
//初始化
const router = new Router({
routes:ROUTES //路由表
});
//全局路由前置守卫
router.beforeEach((to, from, next) => {
next()
})
// 全局路由后置守卫
router.afterEach((to, from) => {
})
export default router;
Echarts饼图之数据展示
1、组件简介
ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。
官网链接:Echarts官网
W3C教程:W3C–Echarts教程
2、前端代码实现
首先,下载库,并引入到项目文件;
话不多说,直接上代码。
/* 封装的组件 HTML代码
<div class="echart-wrap-box">
<div class="echart-content"></div>
</div>
*/
let echarts = require("echarts/echarts.min");
defaults: {
option: {
echartsObj: {},
tooltip: {//提示框浮层内容。
trigger: 'item',//数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
formatter: "{b} : {c}万人"//提示框浮层内容格式器,{a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)
},
//如果系列没有设置颜色,则会依次循环从默认列表中取颜色作为系列颜色。
color: ["#369DFD", "#32C8CA", "#49C872", "#F6CE36", "#EE607A", "#935CE3", "#3436C7", "#3E4D86"],
legend: {//图例组件。
orient: 'vertical',//图例列表的布局朝向:垂直的
x: '80%',//图例组件离容器左侧的距离。
y: '60%',//图例组件离容器上侧的距离。
// width: 100,
textStyle: {},//图例文字的样式
// left: 'right',//图例组件离容器左侧的距离。
top: 'center',//图例组件离容器上侧的距离。
data: [],//右侧图例小组件信息数据
},
series: [{//饼图信息
name: '',
type: 'pie',//饼状图
radius: 140,//饼图的半径。
center: ['50%', '50%'],
minAngle: 5, //最小的扇区角度(0 ~ 360),用于防止某个值过小导致扇区太小影响交互
label: {//展示文本设置
normal: {
show: true,
formatter: "{b} : {c}万人",//视觉引导线内容格式器,{a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)
},
emphasis: { //文本样式
show: true, //展示
textStyle: { //文本样式
fontSize: '16',
fontWeight: '600',
}
}
},
labelLine: {//视觉引导线设置
normal: {
show: true
}
},
data: [],//饼状图信息数据,value(数量)和 name为默认数据;
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}],
},
onInit(event) {
vm = event.vmodel;
let data;//假设这里通过ajax获取到了需要展示的数据;
if (data.length == 0) {
return
}
data = data.sort((a, b) => { return b.number - a.number });//数据根据数量number从大到小排序
if (data.length > 7) {//从大到小的第八个新增粉丝数量的年份 开始统一归为 其他年份新增粉丝数量
let arr = data.slice(7);
let num = 0, rate = 0;
for (let i = 0; i < arr.length; i++) {//第七个之后累数量和比率
num += Number(arr[i].number);
rate += Number(arr[i].rate);
};
let objOtherYear = {
value: num,
name: '其他年份__nana新增粉丝数量',
rate: rate
};
let arr2 = data.slice(0, 7);
arr2.push(objOtherYear);
data = arr2;
data = data.sort((a, b) => { return b.number - a.number });//数据根据数量number从大到小排序
}
this.option.series[0].data = [];
this.option.legend.data = [];
for (let i = 0; i < data.length; i++) {
let seriesData = {
value: 0,
name: '',
rate: ''
};
seriesData.value = data[i].number;
seriesData.name = data[i].year;
seriesData.rate = data[i].rate;
this.option.series[0].data.push(seriesData);//给饼图赋值数据
let legendData = {
name: '',
icon: 'circle',//强制设置图形为:圆形
textStyle: {
color: '#000'
}
}
legendData.name = data[i].year;
this.option.legend.data.push(legendData);//给图例组件赋值数据
}
},
callFun: avalon.noop,//点击饼状图后的回调
isClickEchartsOUt: avalon.noop,//是否为饼图外的点击,父组件进行判断后传过来
onReady(event) {
this.echartsObj = echarts.init(event.target.children[0]);//初始化
this.echartsObj.setOption(this.option);
$(window).resize(() => {
this.echartsObj.resize();
});
let dataIndex;//保存选中扇区的序号
let _this = this;
this.$watch('isClickEchartsOUt', () => {
if (this.isClickEchartsOUt) {//如果不是饼状图扇区的点击,则取消选中;
_this.echartsObj.dispatchAction({
type: 'pieUnSelect',//取消选中指定的饼图扇形。
// 可选,系列 index,可以是一个数组指定多个系列
seriesIndex: 0,
// 可选,数据的 index
dataIndex: dataIndex,
})
}
});
// 处理点击饼图内部的事件
this.echartsObj.on('click', function (params) {
if (params.dataIndex != dataIndex) {//如果不是前一次选中的扇区,则取消选中
_this.echartsObj.dispatchAction({
type: 'pieUnSelect',//取消选中指定的饼图扇形。
// 可选,系列 index,可以是一个数组指定多个系列
seriesIndex: 0,
// 可选,数据的 index
dataIndex: dataIndex,
})
}
dataIndex = params.dataIndex;
_this.echartsObj.dispatchAction({
type: 'pieSelect',//选中指定的饼图扇形。
// 可选,系列 index,可以是一个数组指定多个系列
seriesIndex: 0,
// 数据的 index,如果不指定也可以通过 name 属性根据名称指定数据
dataIndex: dataIndex,
})
vm.callFun(params);//回调,传点击获取到的数据给父组件
});
},
onDispose() {}
}
在我们的日常开发工作中,文本溢出截断省略是很常见的一种需考虑的业务场景细节。看上去 “稀松平常” ,但在实现上却有不同的区分,是单行截断还是多行截断?多行的截断判断是基于行数还是基于高度?这些问题之下,都有哪些实现方案?他们之间的差异性和场景适应性又是如何?
一般来说,在做这样文字截断效果时我们更多是希望:
兼容性好,对各大主流浏览器有好的支持
响应式截断,根据不同宽度做出调整
文本超出范围才显示省略号,否则不显示省略号
省略号位置显示刚好
基于上述的准则,下面我们通过编码实践,给出一些答案。
单行文本溢出省略
核心 CSS 语句
overflow: hidden;(文字长度超出限定宽度,则隐藏超出的内容)
white-space: nowrap;(设置文字在一行显示,不能换行)
text-overflow: ellipsis;(规定当文本溢出时,显示省略符号来代表被修剪的文本)
优点
兼容性好,对各大主流浏览器有好的支持
响应式截断,根据不同宽度做出调整
文本溢出范围才显示省略号,否则不显示省略号
省略号位置显示刚好
短板
只支持单行文本截断,并不支持多行
适用场景
适用于单行文本溢出显示省略号的情况
Demo
<div class="demo">
床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光
</div>
.demo {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
多行文本溢出省略(-webkit-line-clamp)
核心 CSS 语句
overflow: hidden;(文本溢出限定的宽度就隐藏内容)
-webkit-line-clamp: 2;(用来限制在一个块元素显示的文本的行数, 2 表示最多显示 2 行。 为了实现该效果,它需要组合其他的WebKit属性)
display: -webkit-box;(和 -webkit-line-clamp: 2;结合使用,将对象作为弹性伸缩盒子模型显示 )
-webkit-box-orient: vertical;(和 -webkit-line-clamp: 2;结合使用 ,设置或检索伸缩盒对象的子元素的排列方式 )
text-overflow: ellipsis;(多行文本的情况下,用省略号“…”隐藏溢出范围的文本)
优点
响应式截断,根据不同宽度做出调整
文本溢出范围才显示省略号,否则不显示省略号
浏览器原生实现,所以省略号位置显示刚好
短板
兼容性一般: -webkit-line-clamp 属性只有 WebKit 内核的浏览器才支持
适用场景
多适用于移动端页面,因为移动设备浏览器更多是基于 WebKit 内核
Demo
<div class="demo">
床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光
</div>
.demo {
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
多行文本溢出省略(伪元素 + 定位)
核心 CSS 语句
position: relative; (为伪元素绝对定位)
overflow: hidden; (文本溢出限定的宽度就隐藏内容)
position: absolute;(给省略号绝对定位)
line-height: 18px; (结合元素高度,高度固定的情况下,设定行高, 控制显示行数)
height: 36px; (设定当前元素高度)
::after {} (设置省略号样式)
word-break: break-all; (如果文本中有英文,可以使一个单词能够在换行时进行拆分)
优点
兼容性好,对各大主流浏览器有好的支持
响应式截断,根据不同宽度做出调整
短板
无法识别文字的长短,无论文本是否溢出范围,一直显示省略号
省略号显示可能不会刚刚好,有时会遮住一半文字,跟文字没有贴合的很紧密
适用场景
文字内容较多,确定文字内容一定会超过容器的
Demo
<div class="demo">
床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光
</div>
1
2
3
.demo {
position: relative;
line-height: 18px;
height: 36px;
overflow: hidden;
word-break: break-all;
}
.demo::after {
content:"...";
font-weight:bold;
position:absolute;
bottom:0;
right:0;
padding:0 20px 1px 45px;
/ 为了展示效果更好 /
background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(white), color-stop(50%, white));
background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
background: linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
}
多行文本溢出省略(Float)
核心 CSS 语句
line-height: 20px;(结合元素高度,高度固定的情况下,设定行高, 控制显示行数)
overflow: hidden;(文本溢出限定的宽度就隐藏内容)
float: right/left;(利用元素浮动的特性实现)
position: relative;(根据自身位置移动省略号位置, 实现文本溢出显示省略号效果)
word-break: break-all;(如果文本中有英文,可以使一个单词能够在换行时进行拆分)
优点
兼容性好,对各大主流浏览器有好的支持
响应式截断,根据不同宽度做出调整
文本溢出范围才显示省略号,否则不显示省略号
短板
省略号显示可能不会刚刚好,有时会遮住一半文字,跟文字没有贴合的很紧密
适用场景
文字内容较多,确定文字内容一定会超过容器的
Demo
<div class="demo">
<div class="text">
床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光床前明月光
</div>
</div>
.demo {
height: 40px;
line-height: 20px;
overflow: hidden;
}
.demo .text {
float: right;
margin-left: -5px;
width: 100%;
word-break: break-all;
}
.demo::before {
float: left;
width: 5px;
content: "";
height: 40px;
}
.demo::after {
float: right;
content: "...";
height: 20px;
line-height: 20px;
padding-right: 5px;
text-align: right;
width: 3em;
margin-left: -3em;
position: relative;
left: 100%;
top: -20px;
padding-right: 5px;
/ 为了展示效果更好 /
background: -webkit-gradient(
linear,
left top,
right top,
from(rgba(255, 255, 255, 0)),
to(white),
color-stop(50%, white)
);
background: -moz-linear-gradient(
to right,
rgba(255, 255, 255, 0),
white 50%,
white
);
background: -o-linear-gradient(
to right,
rgba(255, 255, 255, 0),
white 50%,
white
);
background: -ms-linear-gradient(
to right,
rgba(255, 255, 255, 0),
white 50%,
white
);
background: linear-gradient(
to right,
rgba(255, 255, 255, 0),
white 50%,
white
);
}
原理
keyCode 对于keypress 事件,该属性声明了被敲击的键生成的 Unicode 字符码。对于 keydown 和 keyup 事件,它指定了被敲击的键的虚拟键盘码。虚拟键盘码可能和使用的键盘的布局相关。 因此我们可以根据keycode返回的字符码来判断用户所按下的键,下面就是一个用于测试上下左右按键的js代码,经过我的测试之后,返回37 38 39 40;
window.onload = function(){
var box = document.getElementById("box");
document.onkeydown = function(event){
event = event || window.event;
console.log(event.keyCode);
}
};
3
3.方块的移动实际上就是坐标的改变,因此需要offsetLeft 和offsetTop 来获得当前方块的坐标,然后将坐标进行一定的更改,就可以实现移动的效果了,下面给出代码
window.onload = function() {
document.onkeydown = function(event) {
event = event || window.event;
//设置移动速度
var speed = 10;
//当ctrl和方向按键同时按下时,提升移动速度
if(event.ctrlKey) {
speed = 50;
}
//获取div
var box01 = document.getElementById("box01");
switch(event.keyCode) {
/*keyCode返回按下按键的编码
* 37 向左
* 38向上
* 39向右
* 40向下
*/
case 37:
box01.style.left = box01.offsetLeft - speed + "px";
break;
case 39:
box01.style.left = box01.offsetLeft + speed + "px";
break;
case 38:
box01.style.top = box01.offsetTop - speed + "px";
break;
case 40:
box01.style.top = box01.offsetTop + speed + "px";
break;
}
};
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box01 {
width: 100px;
height: 100px;
background-color: #008000;
position: absolute;
}
</style>
<script type="text/javascript">
window.onload = function() {
//获取div
var box01 = document.getElementById("box01");
//设置移动速度
var speed = 10;
//设置移动的方向
var dir = 0;
setInterval(function() {
switch(dir) {
/*keyCode返回按下按键的编码
* 37 向左
* 38向上
* 39向右
* 40向下
*/
case 37:
box01.style.left = box01.offsetLeft - speed + "px";
break;
case 39:
box01.style.left = box01.offsetLeft + speed + "px";
break;
case 38:
box01.style.top = box01.offsetTop - speed + "px";
break;
case 40:
box01.style.top = box01.offsetTop + speed + "px";
break;
}
}, 50)
document.onkeydown = function(event) {
event = event || window.event;
//当ctrl和方向按键同时按下时,提升移动速度
if(event.ctrlKey) {
speed = 50;
} else {
speed = 10;
}
//使dir等于keycode的值
dir = event.keyCode;
//当鼠标松开时,停止移动 ---如果不写这一个会造成无法停止移动的效果
document.onkeyup = function() {
dir = 0;
};
};
};
</script>
</head>
<body>
<div id="box01"></div>
</body>
</html>
————————————————
版权声明:本文为CSDN博主「loving-cat」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42878211/article/details/104558443
vuex的基础
1,状态管理(共享)
缓存数据==>内存, 只要刷新页面,数据就丢了
订单,详情等,,,不适用vuex缓存数据
用于
非父子通信的问题
缓存后端数据,提高用户体验
注意:
vuex只能有一个store,
为了防止多人修改,我们切割成子store, 再合并成唯一一个大的store对象
模块写法
import Vue from 'vue'
import Vuex from 'vuex'
import cinema from './module/cinemaModule'
import tabbar from './module/tabbarshowModule'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
}, // "全局"状态
mutations:{
},//唯一修改状态的地方
//异步处理
actions:{
},
// 对上面的“全局状态”进行数据处理, 类似于vue中的计算属性
getters:{
},
modules:{
cinema,
tabbar
}
})
export default store
const module = {
namespaced:true, //命名空间
state :{
cinemaList:[]
},
actions:{
store.commit("setCinemaList",res.data.data.cinemas) //支持传参
},
mutations:{
setCinemaList(state,data){
console.log("setCinemaList",data)
state.cinemaList = data
}
},
getters:{
topDataList(state){
//state形参s, vuex自动调用时候,传来值
return state.cinemaList.slice(0,5)
}
}
}
export default module
import createPersistedState from "vuex-persistedstate"; //在index.js页面加入这个插件
// 加入下面的代码
const store = new Vuex.Store({
plugins: [createPersistedState({
reducer(val){
return {
user: val.user
}
}
})]
————————————————
版权声明:本文为CSDN博主「m0_46436313」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_46436313/article/details/104572076
中介者对象践行了最少知识原则,指一个对象尽可能少的了解别的对象,从而尽量减少对象间耦合程度。这样各个对象只需关注自身实现逻辑,对象间的交互关系交由中介者对象来实现和维护。
需求背景:
手机购买页面,在购买流程中,可以选择手机的颜色及输入购买数量,同时页面有两个展示区域,分别向用户展示刚选择好的颜色和数量。还有一个按钮动态显示下一步的操作,我们需要查询该颜色手机对应的库存,如果库存数量少于这次购买的数量,按钮将被禁用并显示库存不足,反之按钮可以点击并显示放入购物车。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>中介者模式 购买商品</title>
</head>
<body>
选择颜色:
<select id="colorSelect">
<option value="">请选择</option>
<option value="red">红色</option>
<option value="blue">蓝色</option>
</select>
输入购买数量:
<input type="text" id="numberInput">
您选择了颜色:<div id="colorInfo"></div><br>
您输入了数量:<div id="numberInfo"></div><br>
<button id="nextBtn" disabled>请选择手机颜色和购买数量</button>
</body>
<script>
// 最初级的写法
var colorSelect = document.getElementById('colorSelect'),
numberInput = document.getElementById('numberInput'),
colorInfo = document.getElementById('colorInfo'),
numberInfo = document.getElementById('numberInfo'),
nextBtn = document.getElementById('nextBtn');
var goods = {
'red': 3,
'blue': 6
}
colorSelect.onchange = function(){
var color = this.value,
number = numberInput.value,
stock = goods[color]
colorInfo.innerHTML = color;
if(!color){
nextBtn.disabled = true;
nextBtn.innerHTML = '请选择手机颜色';
return;
}
if( ( (number-0) | 0 ) !== number-0 ){ //用户输入的购买数量是否为正整数
nextBtn.disabled = true;
nextBtn.innerHTML = '请输入正确的购买数量';
return;
}
if(number > stock){ //当前选择数量大于库存量
nextBtn.disabled = true;
nextBtn.innerHTML = '库存不足';
return;
}
nextBtn.disabled = false;
nextBtn.innerHTML = '放入购物车';
}
numberInput.oninput = function(){
var color = colorSelect.value,
number = this.value,
stock = goods[color]
colorInfo.innerHTML = color;
if(!color){
nextBtn.disabled = true;
nextBtn.innerHTML = '请选择手机颜色';
return;
}
if( ( (number-0) | 0 ) !== number-0 ){ //用户输入的购买数量是否为正整数
nextBtn.disabled = true;
nextBtn.innerHTML = '请输入正确的购买数量';
return;
}
if(number > stock){ //当前选择数量大于库存量
nextBtn.disabled = true;
nextBtn.innerHTML = '库存不足';
return;
}
nextBtn.disabled = false;
nextBtn.innerHTML = '放入购物车';
}
</script>
</html>
在上个示例中,对象间联系高度耦合,只是两个输入框还好,但如果有多个的话,相互联系就非常复杂了,此时就要考虑用到中介者模式。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>中介者模式 购买商品</title> </head> <body> 选择颜色: <select id="colorSelect"> <option value="">请选择</option> <option value="red">红色</option> <option value="blue">蓝色</option> </select> 选择内存: <select id="memorySelect"> <option value="">请选择</option> <option value="32G">32G</option> <option value="16G">16G</option> </select> 输入购买数量: <input type="text" id="numberInput"> 您选择了颜色:<div id="colorInfo"></div><br> 您选择了内存:<div id="memoryInfo"></div><br> 您输入了数量:<div id="numberInfo"></div><br> <button id="nextBtn" disabled>请选择手机颜色、内存和购买数量</button> </body> <script> var goods = { 'red|32G': 3, 'red|16G': 0, 'blue|32G': 1, 'blue|16G': 6 } //引入中介者 var mediator = (function(){ var colorSelect = document.getElementById('colorSelect'), memorySelect = document.getElementById('memorySelect'), numberInput = document.getElementById('numberInput'), colorInfo = document.getElementById('colorInfo'), memoryInfo = document.getElementById('memoryInfo'), numberInfo = document.getElementById('numberInfo'), nextBtn = document.getElementById('nextBtn'); return { changed: function(obj){ var color = colorSelect.value, memory = memorySelect.value, number = numberInput.value, stock = goods[color + '|' + memory]; if(obj == colorSelect){ //如果改变的是选择颜色下拉框 colorInfo.innerHTML = color; }else if(obj == memorySelect){ memoryInfo.innerHTML = memory; }else if(obj == numberInput){ numberInfo.innerHTML = number; } if(!color){ nextBtn.disabled = true; nextBtn.innerHTML = '请选择手机颜色'; return; } if(!memory){ nextBtn.disabled = true; nextBtn.innerHTML = '请选择手机内存'; return; } if(!number){ nextBtn.disabled = true; nextBtn.innerHTML = '请填写手机数量'; return; } if( ( (number-0) | 0 ) !== number-0 ){ //用户输入的购买数量是否为正整数 nextBtn.disabled = true; nextBtn.innerHTML = '请输入正确的购买数量'; return; } if(number > stock){ //当前选择数量大于库存量 nextBtn.disabled = true; nextBtn.innerHTML = '库存不足'; return; } nextBtn.disabled = false; nextBtn.innerHTML = '放入购物车'; } } })() colorSelect.onchange = function(){ mediator.changed(this) } memorySelect.onchange = function(){ mediator.changed(this) } numberInput.oninput = function(){ mediator.changed(this) } //以后如果想要再增加选项,如手机CPU之类的,只需在中介者对象里加上相应配置即可。 </script> </html>在实际开发中,还是要注意选择利弊,中介者对象因为包含对象间交互的复杂性,所以维护成本可能也会较高。在实际开发中,最优目的还是要快速完成项目交付,而非过度设计和堆砌模式。有时对象间的耦合也是有必要的,只有当对象间复杂耦合确实已经导致调用与维护难以为继,才考虑用中介者模式。
————————————————
版权声明:本文为CSDN博主「一期一会」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34832846/article/details/85989945
蓝蓝设计的小编 http://www.lanlanwork.com