WebAPIs
JavaScript由ECMAScript 和Web APIs(DOM、BOM)组成。ECMAScript 简称 ES ,它提供一套语言标准规范,如变量、数据类型、表达式、语句、函数等语法规则;浏览器将ES的规范加以实现,并扩展一些实用功能,扩展内容被称为Web APIs
Dom获取与属性操作
简介
- DOM将 HTML 文档的每一个标签元素视为一个对象,该对象包含众多属性和方法,通过操作属性和调用这些方法来实现HTML的动态更新。
- 即DOM就是用来动态修改HTML的,其目的是开发网页特效及用户交互。
- DOM树:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>标题</title>
</head>
<body>
文本
<a href="">链接名</a>
<div id="" class="">文本</div>
</body>
</html>
- 文档树:
- DOM节点:节点为文档树的组成部分,每个节点为一个DOM对象,主要分为元素节点、属性节点、文本节点
(1)元素节点:即HTML标签,如
head
、
div
、
body
等
(2)属性节点:即HTML标签中的属性,如
a
标签的
href
属性、
div
标签的
class
属性。
(3)文本节点:HTML 标签的文字内容,如
title
标签中的文字…
- document对象:是DOM里提供的一个对象,该对象包含了若干的属性和方法
<script>
// document 是内置的对象
// console.log(typeof document);
// 1. 通过 document 获取根节点
console.log(document.documentElement); // 对应 html 标签
// 2. 通过 document 节取 body 节点
console.log(document.body); // 对应 body 标签
// 3. 通过 document.write 方法向网页输出内容
document.write('Hello World!');
</script>
获取Dom对象
- 获取一个dom元素:querySelector()
- 获取多个dom元素:querySelectorAll()
<body><h3>查找元素类型节点</h3><p>从整个 DOM 树中查找 DOM 节点是学习 DOM 的第一个步骤。</p><ul><li>元素</li><li>元素</li><li>元素</li><li>元素</li></ul><script>const p = document.querySelector('p')// 获取第一个p元素const lis = document.querySelectorAll('li')// 获取第一个p元素</script></body>
操作元素内容
- 修改元素的文本更换内容
innerText
将文本内容添加/更新到任意标签位置,文本中包含的标签不会被解析
innerHTML
将文本内容添加/更新到任意标签位置,文本中包含的标签会被解析
<body><divclass="box">我是文字的内容</div><script>// 1. 获取元素const box = document.querySelector('.box')// 2. 修改文字内容 对象.innerText 属性// console.log(box.innerText) // 获取文字内容// // box.innerText = '我是一个盒子' // 修改文字内容// box.innerText = '<strong>我是一个盒子</strong>' // 不解析标签,文字不会加粗// 3. innerHTML 解析标签
console.log(box.innerHTML)// box.innerHTML = '我要更换'
box.innerHTML ='<strong>我要更换</strong>'//解析标签,本文会加粗</script></body>
操作元素属性
常用属性修改
<script>// 1. 获取 img 对应的 DOM 元素const pic = document.querySelector('.pic')// 2. 修改属性
pic.src ='./images/lion.webp'
pic.width =400;
pic.alt ='图片不见了...'</script>
控制样式属性
1)通过修改行内样式
style
属性,实现对样式的动态修改
<body><divclass="box"></div><script>// 1. 获取元素const box = document.querySelector('.box')//2. 修改样式属性 对象.style.样式属性 = '值' 别忘了跟单位
box.style.width ='300px'// 多组单词的采取 小驼峰命名法
box.style.backgroundColor ='hotpink'
box.style.border ='2px solid blue'
box.style.borderTop ='2px solid red'</script></body>
2)通过操作类名(className) 操作CSS
<body><divclass="nav">123</div><script>// 1. 获取元素const div = document.querySelector('div')// 2.添加类名 class 是个关键字 我们用 className
div.className ='nav box'</script></body>
3)通过 classList 操作类控制CSS
<body><divclass="box active">文字</div><script>// 通过classList添加// 1. 获取元素const box = document.querySelector('.box')// 2. 修改样式// 2.1 追加类 add() 类名不加点,并且是字符串// box.classList.add('active')// 2.2 删除类 remove() 类名不加点,并且是字符串// box.classList.remove('box')// 2.3 切换类 toggle() 有还是没有啊, 有就删掉,没有就加上
box.classList.toggle('active')</script>
操作表单元素属性
获取:DOM对象.属性名
设置:DOM对象.属性名= 新值
<body>
<input type="text" value="请输入">
<button disabled>按钮</button>
<input type="checkbox" name="" id="" class="agree">
<script>
// 1. 获取元素
let input = document.querySelector('input')
// 2. 取值或者设置值 得到input里面的值可以用 value
// console.log(input.value)
input.value = '小米手机'
input.type = 'password'
// 2. 启用按钮
let btn = document.querySelector('button')
// disabled 不可用 = false 这样可以让按钮启用
btn.disabled = false
// 3. 勾选复选框
let checkbox = document.querySelector('.agree')
checkbox.checked = false
</script>
</body>
自定义属性
- 在html5中推出来了专门的data-自定义属性
- 在标签上一律以data-开头
- 在DOM对象上一律以dataset对象方式获取
<body><divdata-id="1"> 自定义属性 </div><script>// 1. 获取元素let div = document.querySelector('div')// 2. 获取自定义属性值
console.log(div.dataset.id)</script></body>
定时器(间歇函数)
- 能够使用定时器函数重复执行代码
<script>// 1. 定义一个普通函数functionrepeat(){
console.log('不知疲倦的执行下去....')}// 2. 使用 setInterval 调用 repeat 函数// 间隔 1000 毫秒,重复调用 repeatsetInterval(repeat,1000)</script>
Dom事件基础
- 事件是来描述程序的行为或状态的,一旦行为或状态发生改变,便立即调用一个函数。
事件监听
- 获取 DOM 元素
- 通过
addEventListener
方法为 DOM 节点添加事件监听 - 等待事件触发,如用户点击了某个按钮时便会触发
click
事件类型 - 事件触发后,相对应的回调函数会被执行
<body><button>点击</button><script>// 需求: 点击了按钮,弹出一个对话框// 1. 事件源 按钮 // 2.事件类型 点击鼠标 click 字符串// 3. 事件处理程序 弹出对话框const btn = document.querySelector('button')
btn.addEventListener('click',function(){alert('你早呀~')})</script></body>
事件类型
鼠标事件
- 如单击、双击、移动等。
1)mouseenter 监听鼠标是否移入 DOM 元素
2)mouseleave 监听鼠标是否移出 DOM 元素
<body><div></div><script>const div = document.querySelector('div')// 鼠标经过
div.addEventListener('mouseenter',function(){
console.log(`轻轻的我来了`)})// 鼠标离开
div.addEventListener('mouseleave',function(){
console.log(`轻轻的我走了`)})</script></body>
键盘事件
Keydown 键盘按下触发
Keyup 键盘抬起触发
焦点事件
focus 获得焦点
blur 失去焦点
文本框输入事件
input:用户输入事件
<body>
<input type="text">
<script>
const input = document.querySelector('input')
// 1. 键盘事件
// input.addEventListener('keydown', function () {
// console.log('键盘按下了')
// })
// input.addEventListener('keyup', function () {
// console.log('键盘谈起了')
// })
// 2. 用户输入文本事件 input
input.addEventListener('input', function () {
console.log(input.value)
})
</script>
</body>
事件对象
- 事件对象也是个对象,这个对象里有事件触发时的相关信息
- 在事件绑定的回调函数的第一个参数就是事件对象
<body><h3>事件对象</h3><p>任意事件类型被触发时与事件相关的信息会被以对象的形式记录下来,我们称这个对象为事件对象。</p><hr><divclass="box"></div><script>// 获取 .box 元素const box = document.querySelector('.box')// 添加事件监听
box.addEventListener('click',function(e){
console.log('任意事件类型被触发后,相关信息会以对象形式被记录下来...');// 事件回调函数的第1个参数即所谓的事件对象
console.log(e)})</script></body>
环境对象
- 指的是函数内部特殊的变量 this ,它代表着当前函数运行时所处的环境
- 【谁调用, this 就是谁】 是判断 this 指向的粗略规则
- 直接调用函数,其实相当于是 window.函数,所以 this 指代 window
<body><button>点击</button><script>// 每个函数里面都有this 环境对象 普通函数里面this指向的是window// function fn() {// console.log(this)// }// window.fn()const btn = document.querySelector('button')
btn.addEventListener('click',function(){// console.log(this) // btn 对象// btn.style.color = 'red'this.style.color ='red'})</script></body>
回调函数
- 如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数
<script>// 声明 foo 函数functionfoo(arg){
console.log(arg);}// 普通的值做为参数foo(10);foo('hello world!');foo(['html','css','javascript']);functionbar(){
console.log('函数也能当参数...');}// 函数也可以做为参数!!!!foo(bar);</script>
函数
bar
做参数传给了
foo
函数,
bar
就是所谓的回调函数了!!!
Dom事件进阶
事件流
- 事件完整执行过程中的流动路径
事件捕获
- 从DOM的根元素开始去执行对应的事件 (从外到里)
代码:
Dom.addeventlistener(事件类型,事件处理函数,是否使用捕获机制)
事件冒泡
- 当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
<body><divclass="father"><divclass="son"></div></div><script>const fa = document.querySelector('.father')const son = document.querySelector('.son')// 山东 济南 蓝翔 目标(pink老师) 捕获阶段// 蓝翔 济南 山东 冒泡阶段
document.addEventListener('click',function(){alert('我是爷爷')})
fa.addEventListener('click',function(){alert('我是爸爸')})
son.addEventListener('click',function(e){alert('我是儿子')// 组织流动传播 事件对象.stopPropagation()
e.stopPropagation()})</script>
阻止冒泡
- 即阻断事件的流动,保证事件只在当前元素被执行,而不再去影响到其对应的祖先元素
阻止冒泡:事件对象.stopPropagation()
阻止元素默认行为:e.preventDefault()
事件委托
- 事件委托是利用事件流的特征解决一些开发需求的知识技巧
- 原理:利用事件冒泡特点,给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事
- 实现:事件对象.target.tagName→可获得真正触发事件的元素
<body><ul><li>第1个孩子</li><li>第2个孩子</li><li>第3个孩子</li><li>第4个孩子</li><li>第5个孩子</li><p>我不需要变色</p></ul><script>// 点击每个小li 当前li 文字变为红色// 按照事件委托的方式 委托给父级,事件写到父级身上// 1. 获得父元素const ul = document.querySelector('ul')
ul.addEventListener('click',function(e){// alert(11)// this.style.color = 'red'// console.dir(e.target) // 就是我们点击的那个对象// e.target.style.color = 'red'// 我的需求,我们只要点击li才会有效果if(e.target.tagName ==='LI'){
e.target.style.color ='red'}})</script></body>
其它事件
页面加载事件
- 加载外部资源(如图片、外联CSS和JavaScript等)完毕时触发的事件
监听页面所有资源加载完毕:
window.addEventListener('load',function(){// xxxxx})
元素滚动事件
- 滚动条在滚动的时候持续触发的事件
window.addEventListener('scroll',function(){// xxxxx})
页面尺寸事件
- 会在窗口尺寸改变的时候触发事件:
window.addEventListener('resize', function() {
// xxxxx
})
Dom节点&移动端滑动
日期对象
- 用来表示时间的对象,可以得到当前系统时间
实例化
<script>// 实例化 new // 1. 得到当前时间 const date =newDate()
console.log(date)// 2. 指定时间const date1 =newDate('2024-1-1 08:30:00')
console.log(date1)</script>
常用日期对象方法
<script>// 获得日期对象const date =newDate()// 使用里面的方法
console.log(date.getFullYear())
console.log(date.getMonth()+1)// 月份要 + 1
console.log(date.getDate())
console.log(date.getDay())// 星期几</script>
时间戳
- 是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式
//时间戳的三种方式
//1.getTime()
const date = new Date()
console.log(date.getTime())
-----------------------------------------------------
//2.简写 +new Date()
console.log(+new Date())
-----------------------------------------------------
//3.使用Date.now()
//只能得到当前的时间戳, 而前面两种可以返回指定时间的时间戳
console.log(Date.now())
节点操作
插入节点
<body><ul><li>我是老大</li></ul><script>// // 1. 创建节点// const div = document.createElement('div')// // console.log(div)// 2. 追加节点 作为最后一个子元素// document.body.appendChild(div)const ul = document.querySelector('ul')const li = document.createElement('li')
li.innerHTML ='我是li'// ul.appendChild(li)// ul.children// 3. 追加节点// insertBefore(插入的元素, 放到哪个元素的前面)
ul.insertBefore(li, ul.children[0])</script></body>
删除节点
<body><!-- 点击按钮删除节点 --><button>删除节点</button><ul><li>HTML</li><li>CSS</li><li>Web APIs</li></ul><script>const btn = document.querySelector('button')
btn.addEventListener('click',function(){// 获取 ul 父节点let ul = document.querySelector('ul')// 待删除的子节点let lis = document.querySelectorAll('li')// 删除节点
ul.removeChild(lis[0])})</script></body>
Bom操作
简介
- BOM(Browser Object Model ) 是浏览器对象模型
- window对象:一个全局对象,也可以说是JavaScript中的顶级对象
- 如document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的
定时器-延迟函数
- setTimeout只执行一次,可理解为将一段代码延迟执行;
- 间歇函数setInterval : 每隔一段时间就执行一次location对象
- 清除延时函数:
clearTimeout(timerId)
//注:延时函数需要等待,所以后面的代码先执行
<body><script>setTimeout(function(){
console.log('时间到了')},2000)</script>
JS执行机制
- 由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop )
location对象
- 其数据类型是对象,它拆分并保存了 URL 地址的各个组成部分
常用属性和方法:
<body><formaction=""><inputtype="text"name="username"><inputtype="password"name="pwd"><button>提交</button></form><ahref="#/my">我的</a><ahref="#/friend">关注</a><ahref="#/download">下载</a><buttonclass="reload">刷新</button><script>// console.log(window.location)// console.log(location)// console.log(location.href)// 1. href 经常用href 利用js的方法去跳转页面// location.href = 'http://www.baidu.com'const reload = document.querySelector('.reload')
reload.addEventListener('click',function(){// f5 刷新页面// location.reload()// 强制刷新 ctrl+f5
location.reload(true)})</script></body>
navigator对象
其数据类型是对象,该对象下记录了浏览器自身的相关信息
通过 userAgent 检测浏览器的版本及平台
// 检测 userAgent(浏览器信息)
(function () {
const userAgent = navigator.userAgent
// 验证是否为Android或iPhone
const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
// 如果是Android或iPhone,则跳转至移动站点
if (android || iphone) {
location.href = 'http://m.itcast.cn'
}})();
history对象
主要管理历史记录, 该对象与浏览器地址栏的操作相对应,如前进、后退等
<body><button>后退</button><button>前进</button><script>const back = document.querySelector('button:first-child')const forward = back.nextElementSibling
back.addEventListener('click',function(){// 后退一步// history.back()
history.go(-1)})
forward.addEventListener('click',function(){// 前进一步// history.forward()
history.go(1)})</script></body>
本地存储
将数据存储于本地浏览器中
本地存储——localStorage
优点:将数据永久存储在本地(用户的电脑), 除非手动删除,否则关闭页面也会存在
语法:
存储数据:
localStorage.setItem(key, value)
获取数据:
localStorage.getItem(key)
删除数据:
localStorage.removeItem(key)
浏览器查看本地数据
本地存储——sessionStorage
- 用法跟localStorage基本相同,但当页面浏览器被关闭时,存储在 sessionStorage 的数据会被清除
存储:sessionStorage.setItem(key,value)
获取:sessionStorage.getItem(key)
删除:sessionStorage.removeItem(key)
localStorage存储复杂数据类型
难题:本地只能存储字符串,无法存储复杂数据类型
解决:将复杂数据类型转换成 JSON字符串,再在存储到本地
语法:JSON.stringify(复杂数据类型)
<body><script>const obj ={uname:'pink老师',age:18,gender:'女'}// // 存储 复杂数据类型 无法直接使用// localStorage.setItem('obj', obj) [object object] // // 取// console.log(localStorage.getItem('obj'))// 1.复杂数据类型存储必须转换为 JSON字符串存储
localStorage.setItem('obj',JSON.stringify(obj))// JSON 对象 属性和值有引号,而是引号统一是双引号// {"uname":"pink老师","age":18,"gender":"女"}// 取// console.log(typeof localStorage.getItem('obj'))// 2. 把JSON字符串转换为 对象const str = localStorage.getItem('obj')// {"uname":"pink老师","age":18,"gender":"女"}
console.log(JSON.parse(str))</script></body>
数组map方法
可以遍历数组处理数据,并且返回新的数组
<body><script>const arr =['red','blue','green']// map 方法也是遍历 处理数据 可以返回一个数组const newArr = arr.map(function(item, i){// console.log(item) // 数组元素 'red'// console.log(i) // 下标return item +'老师'})
console.log(newArr)['red老师','blue老师','green老师']const arr1 =[10,20,30]const newArr1 = arr1.map(function(item){return item +10})
console.log(newArr1)</script></body>
数组join方法
join() →把数组中的所有元素转换一个字符串
<body><script>const arr =['red','blue','green']// 把数组元素转换为字符串
console.log(arr.join('*'))// red*blue*green</script></body>
正则
正则表达式
是用于匹配字符串中字符组合的模式
语法:
const reg = /表达式/
使用步骤:
<body><script>// 正则表达式的基本使用const str ='web前端开发'// 1. 定义规则const reg =/web/// 2. 使用正则 test()
console.log(reg.test(str))// true 如果符合规则匹配上则返回true
console.log(reg.test('java开发'))// false 如果不符合规则匹配上则返回 false</script></body>
元字符
具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能
如,规定用户只能输入英文26个英文字母,换成元字符写法: /[a-z]/
1)边界符:用来提示字符所处的位置,主要有两个字符
<body><script>// 元字符之边界符// 1. 匹配开头的位置 ^const reg =/^web/
console.log(reg.test('web前端'))// true
console.log(reg.test('前端web'))// false
console.log(reg.test('前端web学习'))// false
console.log(reg.test('we'))// false// 2. 匹配结束的位置 $const reg1 =/web$/
console.log(reg1.test('web前端'))// false
console.log(reg1.test('前端web'))// true
console.log(reg1.test('前端web学习'))// false
console.log(reg1.test('we'))// false //如果 ^ 和 $ 在一起,表示必须是精确匹配// 3. 精确匹配 ^ $const reg2 =/^web$/
console.log(reg2.test('web前端'))// false
console.log(reg2.test('前端web'))// false
console.log(reg2.test('前端web学习'))// false
console.log(reg2.test('we'))// false
console.log(reg2.test('web'))// true
console.log(reg2.test('webweb'))// flase </script></body>
2)量词:用来设定某个模式重复次数
<body><script>// 元字符之量词// 1. * 重复次数 >= 0 次const reg1 =/^w*$/
console.log(reg1.test(''))// true
console.log(reg1.test('w'))// true
console.log(reg1.test('ww'))// true
console.log('-----------------------')// 2. + 重复次数 >= 1 次const reg2 =/^w+$/
console.log(reg2.test(''))// false
console.log(reg2.test('w'))// true
console.log(reg2.test('ww'))// true
console.log('-----------------------')// 3. ? 重复次数 0 || 1 const reg3 =/^w?$/
console.log(reg3.test(''))// true
console.log(reg3.test('w'))// true
console.log(reg3.test('ww'))// false
console.log('-----------------------')// 4. {n} 重复 n 次const reg4 =/^w{3}$/
console.log(reg4.test(''))// false
console.log(reg4.test('w'))// flase
console.log(reg4.test('ww'))// false
console.log(reg4.test('www'))// true
console.log(reg4.test('wwww'))// false
console.log('-----------------------')// 5. {n,} 重复次数 >= n const reg5 =/^w{2,}$/
console.log(reg5.test(''))// false
console.log(reg5.test('w'))// false
console.log(reg5.test('ww'))// true
console.log(reg5.test('www'))// true
console.log('-----------------------')// 6. {n,m} n =< 重复次数 <= mconst reg6 =/^w{2,4}$/
console.log(reg6.test('w'))// false
console.log(reg6.test('ww'))// true
console.log(reg6.test('www'))// true
console.log(reg6.test('wwww'))// true
console.log(reg6.test('wwwww'))// false// 7. 注意事项: 逗号两侧千万不要加空格否则会匹配失败</script>
3)范围:表示字符的范围,定义的规则限定在某个范围
<body><script>// 元字符之范围 [] // 1. [abc] 匹配包含的单个字符, 多选1const reg1 =/^[abc]$/
console.log(reg1.test('a'))// true
console.log(reg1.test('b'))// true
console.log(reg1.test('c'))// true
console.log(reg1.test('d'))// false
console.log(reg1.test('ab'))// false// 2. [a-z] 连字符 单个const reg2 =/^[a-z]$/
console.log(reg2.test('a'))// true
console.log(reg2.test('p'))// true
console.log(reg2.test('0'))// false
console.log(reg2.test('A'))// false// 想要包含小写字母,大写字母 ,数字const reg3 =/^[a-zA-Z0-9]$/
console.log(reg3.test('B'))// true
console.log(reg3.test('b'))// true
console.log(reg3.test(9))// true
console.log(reg3.test(','))// flase// 用户名可以输入英文字母,数字,可以加下划线,要求 6~16位const reg4 =/^[a-zA-Z0-9_]{6,16}$/
console.log(reg4.test('abcd1'))// false
console.log(reg4.test('abcd12'))// true
console.log(reg4.test('ABcd12'))// true
console.log(reg4.test('ABcd12_'))// true// 3. [^a-z] 取反符const reg5 =/^[^a-z]$/
console.log(reg5.test('a'))// false
console.log(reg5.test('A'))// true
console.log(reg5.test(8))// true</script></body>
4)字符类:
替换和修饰符
1)替换语法:
字符串.replace(/正则表达式/,'替换的文本')
2)修饰语法
i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
g 是单词 global 的缩写,匹配所有满足正则表达式的结果
<body><script>// 替换和修饰符const str ='欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'// 1. 替换 replace 需求:把前端替换为 web// 1.1 replace 返回值是替换完毕的字符串// const strEnd = str.replace(/前端/, 'web') 只能替换一个// 2. 修饰符 g 全部替换const strEnd = str.replace(/前端/g,'web')
console.log(strEnd)</script></body>
rue
console.log(reg3.test(‘,’)) // flase
// 用户名可以输入英文字母,数字,可以加下划线,要求 6~16位
const reg4 = /^[a-zA-Z0-9_]{6,16}$/
console.log(reg4.test('abcd1')) // false
console.log(reg4.test('abcd12')) // true
console.log(reg4.test('ABcd12')) // true
console.log(reg4.test('ABcd12_')) // true
// 3. [^a-z] 取反符
const reg5 = /^[^a-z]$/
console.log(reg5.test('a')) // false
console.log(reg5.test('A')) // true
console.log(reg5.test(8)) // true
~~~
4)字符类:
[外链图片转存中…(img-j3SDYxyN-1721007828808)]
[外链图片转存中…(img-a64frONG-1721007828808)]
替换和修饰符
1)替换语法:
字符串.replace(/正则表达式/,'替换的文本')
2)修饰语法
i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
g 是单词 global 的缩写,匹配所有满足正则表达式的结果
<body><script>// 替换和修饰符const str ='欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'// 1. 替换 replace 需求:把前端替换为 web// 1.1 replace 返回值是替换完毕的字符串// const strEnd = str.replace(/前端/, 'web') 只能替换一个// 2. 修饰符 g 全部替换const strEnd = str.replace(/前端/g,'web')
console.log(strEnd)</script></body>
版权归原作者 太阳花ˉ 所有, 如有侵权,请联系我们删除。