03【Web】基础-JavaScript(P3)
本系列文章,针对Web前端的相关知识进行了详细的介绍
前言
这是JavaScript技术有关BOM和DOM的讲解,这些内容虽然在渐进式框架如(Vue、React)中已经弱化为虚拟DOM,但是从理解上学习上实际是变难了,如果跳过这些内容,势必引发学习路线变得陡峭。但是学习这些东西势必又引起学习周期延长。
所以如果没有家庭早期教育的条件或者先天的才能超凡,还请耐住性子反复练习,否则建议早点选择适合自己的道路。
Chapter01 BOM
1.定义
- 浏览器对象模型(Browser Object Model,BOM)定义了JS操作浏览器的接口,提供了与浏览器窗口的交互功能,如获取窗口大小,版本信息,浏览历史记录等。
- 如下图,BOM是用于描述浏览器对象中对象和对象之间层次关系的模型,提供了独立于页面内容并能够与浏览器窗口进行交互的对象结构。
- 其中顶层对象为window,其他对象都是其子对象。当浏览页面时,浏览器会为每个页面自动创建下图中的各个对象
对象 | 作用 |
---|
window | 是BOM模型中的最高一层,通过window对象的属性和方法来实现对浏览器窗口的操作 |
document | 是BOM的核心对象,提供了访问HTML文档对象的属性、方法以及事件处理 |
location | 包含了当前页面的URL地址,如协议,主机名,端口号和路径等信息 |
navigator | 包含与浏览器相关的信息,如浏览器类型和版本等 |
history | 包含历览器历史访问记录,如访问过的URL、访问数量信息等 |
2.windows对象
2.1 常用属性
属性 | 说明 |
---|
name | 窗口的名字 |
length | 窗口内的框架个数 |
innerHeight,innerWidth | 浏览器窗口内部高度和宽度 |
self,top | 当前窗口,当前框架最顶层窗口 |
status | 状态栏信息 |
closed | 判断窗口是否被关闭 |
document,frames, | 4个下级对象 |
scrollbars,toolbar,menubar,locationbar | 滚动条、工具栏、菜单栏、地址栏 |
2.2 常用方法
对象方法 | 说明 |
---|
window.open() | 打开新窗口 |
window.close() | 关闭当前窗口 |
window.moveTo()/ window.moveBy() | 移动当前窗口 |
window.resizeTo()/window.resizeBy() | 调整当前窗口的尺寸 |
focus() / blur() | 得到焦点 / 失去焦点 |
alert(message) | 在对话框中显示 message 消息 |
confirm(message) | 在有OK和Cancle按钮的对话框中显示 message |
prompt(message,response) | 在带有文本输入框的窗口中显示 message |
setTimeout(expression,time) | 在time之后计算expression,time的单位是毫秒 |
clearTimeout(name) | 用名字取消实现暂停 |
setInterval(expression,time) | 每隔time之后计算expression |
clearInterval(name) | 暂停 |
2.3 Open使用
window.open (‘page.html’,‘newwindow’,‘height=100,width=400,top=0,left=0, toolbar=no,menubar=no,scrollbars=no, resizable=no,location=no, status=no’) |
---|
page.html将在新窗体newwindow中打开,宽为100,高为400,距屏顶0象素,屏左0象素, 无工具条,无菜单条,无滚动条,不可调整大小,无地址栏,无状态栏。请对照。 |
3. history,location和navigator
<body>
<h2>8-04 location-history-navigator</h2>
<h4>8-04-1 location</h4>
<div class="panel">
<span>地址栏对象属性</span>
<p>
<script type="text/javascript">
var url = new URL("http://127.0.0.1:5501/01_Html_Web/ShopFashion/knowledge/Chapter08/8-02windowMethod.html?name=guoqy#myAnchor")
document.write("URL:" + url + "对象属性为:<br/>");
document.write("url.protocol:" + url.protocol + "<br/>");
document.write("url.host:" + url.host + "<br/>");
document.write("url.hostname:" + url.hostname + "<br/>");
document.write("url.port:" + url.port + "<br/>");
document.write("url.hash:" + url.hash + "<br/>");
document.write("url.search:" + url.search + "<br/>");
document.write("url.pathname:" + url.pathname + "<br/>");
document.write('<hr />')
</script>
</p>
</div>
<h4>8-04-2 history</h4>
<div id="btngroup">
<a href="./8-01windowProperty.html" class="white">测试历史对象链接</a>
<input type="button" value="forward()前进" onclick="historyForward()">
<input type="button" value="back()后退" onclick="historyBack()">
<input type="button" value="go()前进" onclick="goNext()">
<input type="button" value="go()退后" onclick="goPrevious()">
</div>
<script type="text/javascript">
function goNext() {
history.go(1);
}
function goPrevious() {
history.go(-1);
}
function historyForward() {
history.forward();
}
function historyBack() {
history.back();
}
</script>
<h4>8-04-3 navigator</h4>
<div id="btngroup">
<input type="button" value="Brower" onclick="browserType()">
</div>
<script type="text/javascript">
function browserType() {
var isExists;
var typeInfo = ['MSIE', 'Trident', 'Firefox', 'Chrome', 'safari', 'netscape'];
var explorer = navigator.userAgent;
alert(explorer);
for (let i = 0; i < typeInfo.length; i++) {
if (explorer.indexOf(typeInfo[i]) >= 0) {
isExists = typeInfo[i];
break;
}
}
alert('您的浏览器类型为:' + isExists);
}
</script>
<div class="panel" style="float:left;">
<span>地址栏导航信息</span>
<p>
<script type="text/javascript">
document.write('浏览器:' + navigator.appName + "<br>");
document.write('浏览器版本:' + navigator.appVersion + "<br>");
document.write('浏览器代码:' + navigator.appCodeName + "<br>");
document.write('浏览器平台:' + navigator.platform + "<br>");
document.write('浏览器Cookies启用:' + navigator.cookieEnabled + "<br>");
document.write('浏览器的用户代理报头:' + navigator.userAgent + "<br>");
</script>
</p>
</div>
<script type="text/javascript">
alert("referrer.length:"+document.referrer.length);
</script>
</body>
Chapter02 DOM
1.定义
1.1 DOM
DOM(Document Object Model)是文档对象模型的简称。当网页加载时,可以将结构化文档在内存中转换成对象的树。
简单的说DOM并不是一种技术,而是一种访问结构化文档的思想。借助DOM模型,可以对DOM树进行修改、删除、新增等操作,让结构化文档动态化
1.2 DOM节点
DOM模型中的节点-文档可以说是由节点构成的集合。在DOM模型中有以下三种节点:
- 元素节点:各种标签就是这些元素节点的名称,如:
、
- 属性节点:一般用来修饰元素节点的内容称之为属性节点
- 文本节点:文本节点总是被包含在元素节点的内部
<a title=“JS” href="https://www.baidu.com">百度一下</a>
节点类型 | nodeType | 描述 | 示例 |
---|
元素(Element) | 1 | HTML标签 |
…
|
属性(Attribute) | 2 | HTML标签的属性 | Type=“text” |
文本(Text) | 3 | 文本的内容 | Hello HTML ! |
注释(Comment) | 8 | HTML注释段 |
|
文档(Document) | 9 | HTML文档根节点 | |
文档类型(DocumentType) | 10 | 文档类型 | |
2. 操作HTML元素
2.1 DOM访问节点
为了动态地修改HTML元素,须先访问HTML元素,DOM主要提供两种访问HTML元素的方式:
- 根据ID访问元素-通过document对象调用getElementById()方法来查找具有唯一id属性值的元素。
方法 | 描述 |
---|
open() | 打开一个新文档,并擦除当前文档的内容 |
write() | 向闻到那中写入HTML或JS代码 |
writeln() | 在使用标签是比较有用. 添加的"\n"换行符再HTML中没有有效 |
close() | 关闭一个由open()打开的输出流,并显示选定的数据 |
getElementById() getElementByName() getElementByTagName() getElementByClassName() | 返回一个拥有指定ID的首个对象 返回带有指定名称、指定标签名的对象集合 返回带有指定class属性的对象集合,该方法属于H5 DOM |
querySelector() | 返回满足条件的单个(首个元素) |
querySelectorAll() | 返回满足条件的元素集合 |
- 利用节点的关系访问HTML元素,常见的属性和方法如下:
属性名 | 描述 |
---|
attribute | 返回指定节点的属性集合 |
className | 设置或返回元素的 class 属性 ( 该属性也可获取CSS样式) |
innerHTML | 设置或返回元素内部HTML |
tagName | 返回元素的标签名(始终是大写形式) |
childNodes | 标准属性,返回直接后代的元素节点和文本节点集合,类型为NodeList |
children | 非标准属性,返回直接后代的元素节点的集合,类型为Array |
firstChild | 返回指定节点的首个子节点 |
lastChild | 返回指定节点的最后一个子节点 |
nextSibling | 返回同一父节点的指定节点之后紧跟的节点 |
previousSibling | 返回同一父节点的指定节点之前的一个节点 |
parentNode | 返回指定节点的父节点;当没有父节点时,则返回null |
nodeType | 返回指定节点的节点类型(数值) |
nodeValue | 返回或设置指定节点的节点值 |
方法名 | 描述 |
---|
getElementByTagName() | 返回具有指定标签名的元素子元素集合, 类型为NdoeList |
hasAttribute(“属性名称”) | 指定属性存在时返回true,否则返回false |
getAttribute(“属性名称”) | 返回指定属性对应的属性值 |
removeAttribute(“属性名称”) | 删除指定的元素 |
setAttribute(“名称”,“值”) | 为节点添加属性,当属性存在时,则进行替换 |
hasChildNodes() | 检查元素是否有子节点 |
removeChild() | 删除某个指定的子节点,并返回该节点 |
repalceChild() | 用新节点替换某个子节点 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9-01 通过元素层次关系获取DOM元素节点</title>
<style type="text/css">
#n4{color:#ef0a0a;}
</style>
<script type="text/javascript">
var current;
onload=function(){
current=document.getElementById("n4");
}
function showContent(e){
alert(e.innerHTML);
}
function showCount() {
alert(document.getElementsByTagName('li').length);
}
</script>
</head>
<body>
<ul id="names">
<li id="n1">zhangsan</li>
<li id="n2">lisi</li>
<li id="n3">wangwu</li>
<li id="n4">zhaoliu</li>
<li id="n5">qianqi</li>
<li id="n6">guba</li>
</ul>
<input type="button" value="父节点" onclick="showContent(current.parentNode)">
<input type="button" value="第一个子节点" onclick="showContent(current.parentNode.firstChild.nextSibling)">
<input type="button" value="上一个节点" onclick="showContent(current.previousSibling.previousSibling)">
<input type="button" value="下一个节点" onclick="showContent(current.nextSibling.nextSibling)">
<input type="button" value="最后一个子节点" onclick="showContent(current.parentNode.lastChild.previousSibling)">
<input type="button" value="li元素个数" onclick="showCount()">
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSP基础-设置CSS</title>
<style type="text/css">
.box{
width:100px;
height: 100px;
text-align: center;
line-height: 100px;
}
.box1{
color: green;
}
</style>
<script type="text/javascript">
onload=function (){
var div= document.getElementsByTagName("div")[0];
div.style.color="red";
div.style.border="1px solid";
div.style.backgroundColor="gold";
div.style.fontsize="30px";
div.className="box";
div.className+=" box1";
}
</script>
</head>
<body>
<div>好好</div>
</body>
</html>
2.2 DOM操作节点
document.createElement(Tag);
cloneNode(boolean deep);
方法 | 说明 |
---|
appendChild(newNode) | 将newNode添加成当前节点的最后一个子节点 |
insertBefore(newNode,refNode) | 在refNdoe节点之前插入newNode节点 |
repalceChild(newNode,oldNode) | 在oldNode节点替换成newNode节点 |
removeChild(oldNode) | 将oldNode子节点删除 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9-05 DOM操作节点- 创建|复制|删除|添加</title>
<script type="text/javascript">
function creatNode () {
var city= document.getElementById("city");
var elementli=document.createElement("li");
elementli.innerHTML="南京";
city.appendChild(elementli);
}
function insertNode(){
var city=document.getElementById('city');
var elementli=document.createElement("li");
elementli.innerHTML="长安";
city.insertBefore(elementli,city.firstChild.nextSibling);
}
function repalceNode() {
var city=document.getElementById('city');
var elementli=document.createElement("li");
elementli.innerHTML="广阳";
city.replaceChild(elementli,city.lastChild.previousSibling);
}
function copyNode() {
var city=document.getElementById('city');
var elementli=city.firstChild.nextSibling.cloneNode(true);
city.appendChild(elementli);
}
function deleteNode(){
var city=document.getElementById('city');
city.removeChild(city.firstChild.nextSibling);
}
onload=function(){
var btnCreate= document.getElementById('btnCreate');
var btnInsert= document.getElementById('btnInsert');
var btnReplace= document.getElementById('btnReplace');
var btnCopy= document.getElementById('btnCopy');
var btnDelete= document.getElementById('btnDelete');
btnCreate.onclick=creatNode;
btnInsert.onclick=insertNode;
btnReplace.onclick=repalceNode;
btnCopy.onclick=copyNode;
btnDelete.onclick=deleteNode;
}
</script>
</head>
<body>
<ul id="city">
<li>北京</li>
<li>上海</li>
</ul>
<input type="button" id="btnCreate" value="创建节点" >
<input type="button" id="btnInsert" value="插入节点" >
<input type="button" id="btnReplace" value="替换节点" >
<input type="button" id="btnCopy" value="复制节点">
<input type="button" id="btnDelete" value="删除节点">
</body>
</html>
2.3 访问表单控件
属性和方法 | 说明 |
---|
action | 返回该表单提交的地址 |
elements | 返回表单内部全部表单控件所组成的数组,通过数组访问表单内的任何控件 |
length | 返回表单内表单域的个数 |
method | 返回表单内的method属性,主要是get 和 post两个值 |
target | 设置提交表单时的结果窗口,主要有 : _ self、 _ blank、_ top、 |
reset()、submit() | 重置表单和确定表单提交 |
- 在 elements 返回的数组种访问具体的表单控件语法:
elements的访问方式 | 说明 |
---|
.elements[index] | 返回该表单中index个表单控件 |
.elements[elementName] | 返回表单内id或name为elementName的表单控件 |
.elementName | 返回表单中id或name为elementName的表单控件 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9-02 获取DOM种表单的相关控件</title>
<script type="text/javascript">
function operatorForm() {
var myform = document.forms[0];
alert(myform.action);
alert(myform.method);
alert(myform.target);
myform.submit();
}
function resetForm() {
var myform = document.forms[0];
myform.reset();
}
</script>
</head>
<body>
<form id="formID" action="https://www.baidu.com/" method="get"
target="_blank">
<input type="text" name="username" value="cloudwhales">
<input type="password" name="password" value="123456">
<select name="city" id="">
<option value="beijing">北京</option>
<option value="shanghai" selected>上海</option>
</select>
<br>
<input type="button" value="获取表单内第一个控件" onclick="alert(document.getElementById('formID').elements[0].value);">
<input type="button" value="获取表单内第二个控件"
onclick="alert(document.getElementById('formID').elements['password'].value);">
<input type="button" value="获取表单内第三个控件" onclick="alert(document.getElementById('formID').city.value);">
<input type="button" value="操作表单" onclick="operatorForm()">
<input type="button" value="重置表单" onclick="document.forms[0].reset()">
</form>
</body>
</html>
2.4 访问列表框, 下拉菜单
属性 | 说明 |
---|
form | 返回列表框,下拉菜单所在的表单对象 |
length | 返回列表框,下拉菜单的选项个数 |
options | 返回列表框,下拉菜单里所有选项组成的数组 |
selectedIndex | 返回下拉列表中选项的索引 |
type | 返回列表框的类型,多选返回select-muliple,单选返回select-more |
- 使用 options[index] 返回具体选项所在的常用属性
属性 | 说明 |
---|
defaultSelected | 返回该选项默认 是否 被选中 |
index | 返回该选项在列表框,下拉菜单中的索引 |
selected | 返回该选项 是否 被选中 |
text | 返回该选项呈现的文本 |
value | 返回该选项的value属性值 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9-03 列表框、下拉菜单的访问</title>
<script type="text/javascript">
var s_city;
onload = function () {
s_city = document.getElementById('city');
}
var change = function (city) {
alert(city.text);
}
</script>
</head>
<body>
<select name="city" id="city" size="5">
<option value="beijing">北京</option>
<option value="shanghai" selected>上海</option>
<option value="tianjin">天津</option>
<option value="nanjing">南京</option>
<option value="shenzhen">深圳</option>
<option value="wuhan">武汉</option>
</select>
<br>
<input type="button" value="第一个城市" onclick="change(s_city.options[0]);">
<input type="button" value="上一个城市" onclick="change(s_city.options[s_city.selectedIndex-1]);">
<input type="button" value="下一个城市" onclick="change(s_city.options[s_city.selectedIndex+1]);">
<input type="button" value="最后一个城市" onclick="change(s_city.options[s_city.length-1]);">
</body>
</html>
2.5 操作列表框,下拉菜单的选项
new Option(text,value,defaultSelected,selected);
new Option(text.value);
new Option(text);
参数 | 说明 | 参数 | 说明 |
---|
text | 该选项的文本、即该选项所呈现的“内容” | value | 选中该选项的值 |
defaultSelected | 设置默认是否显示该选项 | selected | 设置该选项当前是否被选中 |
[object].remove(index);
[object].options[index]=null;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9-05 DOM操作列表框和下拉列表选项</title>
<script type="text/javascript">
function createSelect(){
var select=document.createElement('select');
for (let i = 0; i < 10; i++) {
var optionItem=new Option("新增的选项"+i,i);
select.options[i]=optionItem;
}
select.size=5;
select.id='city';
var test= document.getElementById('test');
test.insertBefore(select,test.firstChild.nextSibling);
}
function deleteOption() {
var select=document.getElementById('city');
if(select.options.length>0){
select.remove(select.options.length-1);
}
}
function deleteAllOptions(){
var select=document.getElementById('city');
if(select.options.length>0){
select.options.length=0;
}
}
onload=function(){
var btnCreate=document.getElementById('btnCreate');
var btnDelete=document.getElementById('btnDelete');
var btnDeleteAll=document.getElementById('btnDeleteAll');
btnCreate.onclick=createSelect;
btnDelete.onclick=deleteOption;
btnDeleteAll.onclick=deleteAllOptions;
}
</script>
</head>
<body id="test">
<br>
<input type="button" id="btnCreate" value="创建一组城市列表">
<input type="button" id="btnDelete" value="逐条删除列表项">
<input type="button" id="btnDeleteAll" value="一次性清空全部列表项">
</body>
</html>
2.6 访问及操作表格及表格的行和列
属性 | 说明 |
---|
caption | 返回表格的标题对象 |
rows | 返回表格里的所有表格行 |
tboby | 返回表格里所有tbody元素组成的数组 |
tfoot | 返回表格里所有tfoot元素 |
thead | 返回表格里所有thead元素 |
- 通过 rows[index] 返回表格指定的行所对应的属性
行属性 | 说明 |
---|
cells | 返回该表格内所有的单元格组成的数组 |
rowIndex | 返回该表格行在表格内的索引 |
sectionRowIndex | 返回该表格行在其所在元素(tbody、thead等元素)的索引值 |
- 通过 cells[index] 返回表格指定的列对应的属性:
列属性 | 说明 |
---|
cellsIndex | 返回该单元格在表格行内的索引值 |
常用方法 | 说明 |
---|
insertRow(index) | 在表格的指定位置插入一行 新插入行在index之前,参数index不可小于0或超出索引 |
deleteRow(index) | 从表格中删除指定的行 |
createCaption() | 从表格删除caption元素 |
deleteCaption() | 从表格删除caption元素 |
createTHead() | 从表格删除thead元素 |
deleteTHead() | 从表格删除thead元素 |
createTFoot() | 从表格删除tfoot元素 |
daleteTFoot() | 从表格删除tfoot元素 |
常用方法 | 说明 |
---|
insertCell() | 在HTML表中一行的指定位置插入一个空的td |
deleteCell() | 删除单行行的单元格 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9-04 操作表格元素及子元素</title>
<script type="text/javascript">
function updatecell(){
var rowindex=document.getElementById("row").value;
var cellindex=document.getElementById("cell").value;
var tb=document.getElementById('mytable');
tb.rows.item(rowindex-1).cells.item(cellindex-1).innerHTML=document.getElementById('name').value;
}
</script>
</head>
<body>
<table id="mytable" border="1">
<caption>表格示例</caption>
<tr><td>C</td><td>C++</td></tr>
<tr><td>LSD</td><td>ARM</td></tr>
<tr><td>J2EE</td><td>C#.net</td></tr>
</table>
<input type="button" value="表格标题" onclick="alert(document.getElementById('mytable').caption.innerHTML);">
<input type="button" value="第一行,第一列" onclick="alert(document.getElementById('mytable').rows[0].cells[0].innerHTML);">
<input type="button" value="第二行,第二列" onclick="alert(document.getElementById('mytable').rows[1].cells[1].innerHTML);">
<input type="button" value="第三行,第二列" onclick="alert(document.getElementById('mytable').rows[2].cells[1].innerHTML);">
<br> 修改表格元素内容:将<br>
第 <input type="text" id="row" size="2"> 行,
第 <input type="text" id="cell" size="2"> 列,
改为: <input type="text" id="name" size="10"> <br>
<input type="button" value="确认修改" id="btnSet" onclick="updatecell()">
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9-05 操作表格行列</title>
<script type="text/javascript">
function createTable(){
var main=document.getElementById('main');
var tb = document.createElement("table");
tb.border=1;
tb.id="mytable";
var caption= tb.createCaption();
caption.innerHTML="创建5*4的表格";
for (let i = 0; i < 5; i++) {
var tbody= tb.createTBody();
var row=tbody.insertRow();
for (let j = 0; j < 4; j++) {
var cell = row.insertCell();
cell.innerHTML="("+i+","+j+")";
}
}
main.insertBefore(tb,main.firstChild.nextSibling);
}
function deleteRow(){
var table=document.getElementById("mytable");
if(table.rows.length>0){
table.deleteRow(table.rows.length-1);
}
}
function deleteCell(){
var table=document.getElementById("mytable");
if(table.rows.length>0){
var lastRow=table.rows[table.rows.length-1];
if(lastRow.cells.length>0){
lastRow.deleteCell(lastRow.cells.length-1);
}
}
}
onload=function(){
var btnCreate=document.getElementById('btnCreate');
var btnDeleteRow=document.getElementById('btnDeleteRow');
var btnDeleteCells=document.getElementById('btnDeleteCells');
btnCreate.onclick=createTable;
btnDeleteRow.onclick=deleteRow;
btnDeleteCells.onclick=deleteCell;
}
</script>
</head>
<body id="main">
<br>
<input type="button" id="btnCreate" value="创建一个5*4的表格">
<input type="button" id="btnDeleteRow" value="删除表格最后一行">
<input type="button" id="btnDeleteCells" value="删除最后一个单元格">
</body>
</html>
总结
以上就是【Web】基础-JavaScript技术有关BOM和DOM的介绍