<!-- 请实现一个简单的事件机制,能够实现对事件的触发和监听。
如:EventEmitter.on(); EventEmitter.trigger(); -->
<script>
const EventEmitter = {
on: function(type, handle) {
//创建一个缓存
this.cache = {};
console.log(this);
//判断是否有这个类型的事件
if (!this.cache[type]) {
//没有则创建一个
this.cache[type] = [handle];
} else {
//已经存在就推入
this.cache[type].push(handle);
}
},
trigger: function(type) {
//判断是否传入了参数,如果传入了就把它填进一个数组中
var params = arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [];
if (this.cache[type]) {
this.cache[type].forEach(item => {
//执行函数,并将参数传入
item(params);
})
}
}
}
</script>
<script>
function mynews(Func, ...args) {
const obj = {};
obj.__proto__ = Func.prototype;
let result = Func.apply(obj, args);
return result instanceof Object ? result : obj;
}
</script>
<script>
//创建XMLHttprequest()对象
var ajax = new XMLHttpRequest();
//设置请求的方式,url,是否异步
ajax.open("GET", url, true);
//发送信息至服务器时内容编码类型
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//发送请求
ajax.send();
//接受服务器响应数据
ajax.onreadystatechange = () => {
};
</script>
<div id=“box”>
<span> 1 </span><span> 2
</span><span> 3 </span>…<span> 1000 </span>
</div>
<script>
var box = document.querySelector('#box');
box.addEventListener('click',
function(e) {
var target = e.target;
if (target.nodeName.toLowerCase() === 'span') {
alert(target.innerText);
}
}, false);
</script>
<script>
let fs = require("fs");
let evenobj = {
arr: [],
on(event, fn) {
// if(this.arr[event]){
// this.arr[event].push(fn);
// }else{
// this.arr[event]=[];
// this.arr[event].push(fn);
// }
(this.arr[event] || (this.arr[event] = []).push(fn))
},
emit() {
let event = [].shift.call(arguments);
if (this.arr[event]) {
this.arr[event].forEach(fn => fn.apply(this.arguments));
}
}
}
evenobj.on("data1", function(x) {
console.log("订阅1" + x);
});
fs.readFile("1.txt", (err, res) => {
evenobj.emit("data1", res);
});
</script>
<script>
// 1)防抖
// 原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
// 适用场景:
// 按钮提交场景:防止多次提交按钮,只执行最后提交的一次
// 搜索框联想场景:防止联想发送请求,只发送最后一次输入
// 简易版实现
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout)
timeout = setTimeout(function() {
func.apply(context, args)
}, wait);
}
}
// 立即执行版实现
// 有时希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行。
// 有时希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行。
function debounce(func, wait, immediate) {
let timeout;
return function() {
const context = this;
const args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
const callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
} else {
timeout = setTimeout(function() {
func.apply(context, args)
}, wait);
}
}
}
// 返回值版实现
// func函数可能会有返回值,所以需要返回函数结果,但是当 immediate 为 false 的时候,
//因为使用了 setTimeout ,我们将 func.apply(context, args) 的返回值赋给变量,最后再 return 的时候,
//值将会一直是 undefined,所以只在 immediate 为 true 的时候返回函数的执行结果。
function debounce(func, wait, immediate) {
let timeout, result;
return function() {
const context = this;
const args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
const callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args)
} else {
timeout = setTimeout(function() {
func.apply(context, args)
}, wait);
}
return result;
}
}
// 2)节流
// 原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
// 适用场景
// 拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
// 缩放场景:监控浏览器resize
// 使用时间戳实现
// 使用时间戳,当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0 ),
//如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。
function throttle(func, wait) {
let context, args;
let previous = 0;
return function() {
let now = +new Date();
context = this;
args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
// 使用定时器实现
// 当触发事件的时候,我们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,
//然后执行函数,清空定时器,这样就可以设置下个定时器。
function throttle(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
if (!timeout) {
timeout = setTimeout(function() {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
</script>
<script>
function fib(n) {
if (n < 0) throw new Error('输入的数字不能小于0');
if (n < 2) {
return n;
}
let list = [];
list[0] = 0;
list[1] = 1;
for (let i = 1; i < n; i++) {
list[i + 1] = list[i] + list[i - 1];
}
return list[n];
}
</script>
<script>
function foo(arr) {
let AMOUNT = arr.length
if (!AMOUNT) return false;
if (AMOUNT === 3) return arr;
arr.sort((a, b) => a - b);
let total = 0;
let maxNumberTotal = 0;
for (let i = 0; i < AMOUNT; i++) {
total += arr[i];
}
maxNumberTotal = total / 3;
let tempTotal = arr[AMOUNT - 1];
let firstArr = [arr[AMOUNT - 1]];
let delIndex = [AMOUNT - 1];
let firstIndex = -1;
// 获取第一份数组
for (let i = AMOUNT - 2; i > 0; i--) {
const el = arr[i];
tempTotal += el; // 每次拿最大的;
firstArr.push(el);
delIndex.push(i);
if (tempTotal === maxNumberTotal) { // 刚好等于最大值跳出循环
break;
} else if (tempTotal > maxNumberTotal) { // 发现超过最大值, 减回去
tempTotal -= el;
delIndex.pop();
firstArr.pop();
} else if (tempTotal < maxNumberTotal) { // 发现超过最小值, 处理边界问题
let nextTotal = tempTotal + arr[i + 1]
if (maxNumberTotal - tempTotal < Math.abs(maxNumberTotal - nextTotal)) { // 当前总值比上一个总值大; 这里是临界值, 说明上一个总值肯定是一个比最大值大, 所以这里需要和绝对值比较
if (maxNumberTotal - tempTotal > arr[0]) { // 如果下一个平局值和总值相减, 比数组第一个数还大, 说明还可以继续走下去;
continue;
} else {
break;
}
}
}
}
for (let i = 0; i < delIndex.length; i++) {
arr.splice(delIndex[i], 1)
}
AMOUNT = arr.length; // 注意每次的arr都是不一样的
let secondArr = [arr[AMOUNT - 1]];
delIndex = [AMOUNT - 1];
let secondIndex = -1;
tempTotal = arr[AMOUNT - 1];
// 获取第二份数组
for (let i = AMOUNT - 2; i > 0; i--) {
const el = arr[i];
tempTotal += el; // 每次拿最大的;
secondArr.push(el);
delIndex.push(i);
if (tempTotal === maxNumberTotal) { // 刚好等于最大值跳出循环
break;
} else if (tempTotal > maxNumberTotal) { // 发现超过最大值, 减回去
tempTotal -= el;
delIndex.pop();
secondArr.pop();
} else if (tempTotal < maxNumberTotal) { // 发现超过最小值, 处理边界问题
let nextTotal = tempTotal + arr[i + 1]
if (maxNumberTotal - tempTotal < Math.abs(maxNumberTotal - nextTotal)) { // 当前总值恒小于下一个总值; 这里是临界值
if (maxNumberTotal - tempTotal > arr[0]) {
continue;
} else {
break;
}
}
}
}
for (let i = 0; i < delIndex.length; i++) {
arr.splice(delIndex[i], 1)
}
// 公平处理, 当出现极差情况就需要做公平处理了, 这里暂时不考虑极差情况
return [firstArr, secondArr, arr]
}
</script>
<script>
var obj = {};
function CJDX(name, age, sex) {
// var obj = new Object();
this.name = name;
this.age = age;
this.sex = sex;
// obj.sayName = function() {
// };
// return obj;
};
//原型中添加公共的方法,提高运行效率
CJDX.prototype.sayName = function() {
console.log("我是谁:" + this.name);
//console.log("nihao");
}
var frist = new CJDX("孙悟空", 18, "男");
var second = new CJDX("猪八戒", 20, "男");
var three = new CJDX("沙和尚", 28, "男");
frist.sayName();
</script>
<script>
// let arr = [11, [1, 2, 3], 11, [1, 4, 5, [76, 8, 9, 0]]];
// //扁平化处理
// let arr1 = arr.toString().split(',').map(item => parseFloat(item));
// //去重
// let result = [...new Set(arr1)];
// //排序
// let pai=
// console.log(result);
/**
* 解题思路:
* 双指针 从头到尾比较 两个数组的第一个值,根据值的大小依次插入到新的数组中
* 空间复杂度:O(m + n)
* 时间复杂度:O(m + n)
* @param {Array} arr1
* @param {Array} arr2
*/
function merge(arr1, arr2) {
var result = [];
while (arr1.length > 0 && arr2.length > 0) {
if (arr1[0] < arr2[0]) {
/*shift()方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。*/
result.push(arr1.shift());
} else {
result.push(arr2.shift());
}
}
return result.concat(arr1).concat(arr2);
}
function mergeSort(arr) {
let lengthArr = arr.length;
if (lengthArr === 0) {
return [];
}
while (arr.length > 1) {
let arrayItem1 = arr.shift();
let arrayItem2 = arr.shift();
let mergeArr = merge(arrayItem1, arrayItem2);
arr.push(mergeArr);
}
return arr[0];
}
let arr1 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[1, 2, 3],
[4, 5, 6]
];
let arr2 = [
[1, 4, 6],
[7, 8, 10],
[2, 6, 9],
[3, 7, 13],
[1, 5, 12]
];
mergeSort(arr1);
console.log(arr1);
mergeSort(arr2);
</script>
<!--
基本的垃圾回收算法为“标记-清除”,定期执行垃圾回收
第一步:标记空间中的【可达】值
--V8 采用的是可达性 (reachability) 算法来判断堆中的对象应不应该被回收。
这个算法的思路是这样的:
----从根节点(Root)出发,遍历所有的对象。
---可以遍历到的对象,是可达的(reachable)。
---没有被遍历到的对象,不可达的(unreachable)。
---在浏览器环境下,根节点有很多,主要包括这几种:
全局变量 window,位于每个 iframe 中
文档 DOM 树
存放在栈上的变量
…
这些根节点不是垃圾,不可能被回收。
第二步:回收 不可达 的值占用的内存
--在所有的标记完成之后,统一清理内存中所有不可达的对象。
.第三步,做内存整理
1 在频繁回收对象后,内存中就会存在大量不连续空间,专业名词叫「内存碎片」。
2 当内存中出现了大量的内存碎片,如果需要分配较大的连续内存时,就有可能出现内存不足的情况。
3 所以最后一步是整理内存碎片。(但这步其实是可选的,因为有的垃圾回收器不会产生内存碎片,比如接下来我们要介绍的副垃圾回收器。)
------什么时候进行垃圾回收
浏览器进行垃圾回收的时候,会暂停 JavaScript 脚本,等垃圾回收完毕再继续执行。
对于普通应用这样没什么问题,但对于 JS 游戏、动画对连贯性要求比较高的应用,如果暂停时间很长就会造成页面卡顿。
这就是我们接下来谈的关于垃圾回收的问题:什么时候进行垃圾回收,可以避免长时间暂停。
-->
<script>
// 原型关系和原始值转换
let arrayLike = {
length: 10,
};
console.log(arrayLike instanceof Array); // false
console.log(arrayLike.__proto__.constructor === Array); // false
console.log(arrayLike.toString()); // [object Object]
console.log(arrayLike.valueOf()); // {length: 10}
let array = [];
console.log(array instanceof Array); // true
console.log(array.__proto__.constructor === Array); // true
console.log(array.toString()); // ''
console.log(array.valueOf()); // []
</script>
3)类数组转换为数组<br> 转换方法
<br> 使用 Array.from()<br> 使用 Array.prototype.slice.call()<br> 使用 Array.prototype.forEach() 进行属性遍历并组成新的数组<br> 转换须知
<br> 转换后的数组长度由 length 属性决定。索引不连续时转换结果是连续的,会自动补位。<br> 代码示例
<br>
<script>
let al1 = {
length: 4,
0: 0,
1: 1,
3: 3,
4: 4,
5: 5,
};
console.log(Array.from(al1)) // [0, 1, undefined, 3]
</script>
<script>
//求字符串 'hello world' 对应的ASCII码数组,并按照编码大小逆序。
//输入: 'hello world’
//输出:[119, 114, 111, 111, 108, 108, 108, 104, 101, 100, 32]
const str = 'hello world';
const array = str.split('').map(letter => {
return
letter.charCodeAt();
}).sort(function() {
return arguments[1] - arguments[0];
}
</script>
<script>
const getUglyNumber = n => {
if (n >= 1) {
const temp = [1],
result = [1];
let i = 1,
index2 = 0,
index3 = 0,
index5 = 0;
while (result.length < n) {
temp[i] = Math.min(temp[index2] * 2, temp[index3] * 3, temp[index5] * 5);
if (temp[i] == temp[index2] * 2) {
index2++;
} else if (temp[i] == temp[index3] * 3) {
index3++;
} else if (temp[i] == temp[index5] * 5) {
index5++;
}
if (result.indexOf(temp[i]) == -1) {
result.push(temp[i]);
}
i++;
}
return result[n - 1];
}
}
</script>
<script>
console.time("test");
var number = parseInt(prompt("请输入一个大于一的数字:"));
if (number <= 1) {
alert("请输入一个大于一的数字:");
var number = parseInt(prompt("请输入一个大于一的数字:"));
} else {
var flag = true;
for (var i = 2; i < number; i++) {
for (var j = 2; j <= Math.sqrt(number); j++) {
if (number % j == 0) {
//则不是质数
flag = false;
break;
}
}
}
if (flag) {
alert(number + "是质数");
} else {
alert(number + "不是质数");
}
}
console.timeEnd("test");
</script>
<script>
var arr = [100, 108, 90, 88, 101, 80, 89, 86];
var max = 0,
first = 0,
end = 0;
arr.forEach((item, i) => {
for (var j = i + 1; j < arr.length; j++) {
if (arr[j] - item > max) {
max = arr[j] - item;
first = i;
end = j;
}
}
if (i == arr.length - 1) {
console.log('在第' + first + '次买入,' + '在第' + end + '次卖出,' + '可获得最高利润' + max);
}
})
</script>
<script>
// debugger
function maxNum(numArr) {
for (var i = 0; i < numArr.length - 2; i++) {
// console.log(numArr[i + 1].toString().length)
// if (numArr[i].toString().length == 1 && (numArr[i].toString()[0] == numArr[i + 1].toString()[0])) {
// var k = numArr[i + 1];
// numArr[i + 1] = numArr[i];
// numArr[i] = k;
// }
}
console.log(numArr)
var newArr = numArr.reverse().join('');
//console.log(typeof newArr);
return newArr;
}
console.log(maxNum([21, 35, 34, 86, 9, 8, 7]));
//console.log(typeof newArr);
</script>
<script>
var str = " Hello World! ";
alert(str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''));
</script>
<script>
const str = 'asddfgdfwwqeweqwezczxcsdfgdgd';
let map = {};
let maxTimes = 0,
target;
for (let i = 0; i < str.length; i++) {
if (map[str[i]] !== undefined) {
map[str[i]]++;
} else {
map[str[i]] = 1;
}
if (map[str[i]] > maxTimes) {
maxTimes = map[str[i]];
target = str[i];
}
}
map = null;
console.log(target, maxTimes);
</script>
<!-- 编写 JavaScript 函数,其唯一的输入参数为URL字符串,函数返回一个对象。返回对象中的属性包括 URL 中的
全部查询字符串(Query)字段。例如,输入字符串 “https://www.yonyoucloud.com?name=yonyou&location=beijing” 返回
{ name: “yonyou”, location: “beijing” } -->
<script>
var url =
'https://www.yonyoucloud.com?name=yonyou&location=beijing';
var obj = parseQueryString(url);
function parseQueryString(argu) {
var str = argu.split('?')[1];
console.log(str);
var result = {};
var temp = str.split('&');
console.log(temp);
for (var i = 0; i < temp.length; i++) {
var temp2 = temp[i].split('=');
result[temp2[0]] = temp2[1];
}
return result;
}
console.log(obj);
</script>
<!-- 原型链是用来查找(实例)对象属性 -->
<script>
function Fn() { //内部语句:this.prototype={};
}
//每个函数都有一个显示原型prototype:默认指向一个空的object(实例)对象。
console.log(Fn.prototype);
var fn = new Fn(); //内部语句:this.__proto__=Fn.prototype
//每个实例都有一个隐式原型:__proto__
console.log(fn.__proto__);
//对象的显示原型等于实例的隐式原型
//实例对象的隐式原型等于构造函数的显示原型
console.log(Fn.prototype === fn.__proto__); //true
Fn.prototype.test = function() {
console.log('test');
}
fn.test(); //test
//显示原型指向的对象默认是空object实例对象(但object不满足);
console.log(Fn.prototype instanceof Object); //true
console.log(Object.prototype instanceof Object); //false
console.log(Function.prototype instanceof Object); //true
//所有的函数都是Function的实例(包含Function)
console.log(Function.__proto__ === Function.prototype); //true
//Object的原型对象是原型链的尽头
console.log(Object.prototype.__proto__); //null
//读取对象的属性值时:会自动到原型链上查找
//设置对象属性值时:不会查找原型链,如果当前对象没有次属性,则直接添加属性并且设置值
//方法一般定义在原型中,属性一般通过构造函数定义在对象的本身上。
</script>
<script>
function A() {
}
A.prototype.n = 1;
//实例b还是指向的A的旧的对象
var b = new A();
//此时A指向了一个新的对象
A.prototype = {
n: 1,
m: 2
}
//实例c指向的是A的新的对象
var c = new A();
console.log(b.n, b.m, c.n, c.m); //1 undefined 1 2
</script>
<script>
function F() {}
Object.prototype.a = function() {
console.log('bbb');
}
Function.prototype.B = function() {
console.log('bbbbb');
}
var f = new F();
f.a(); //bbb
f.B(); //报错
F.a(); //bbb
F.B(); //bbbbb
console.log();
</script>
<!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>Document</title>
<style>
/* .fuji {
width: 100px;
display: flex;
background-color: blue;
justify-content: center;
align-items: center;
}
.zi {
margin: auto;
justify-content: center;
} */
/* 第一种: 利用margin定位*/
/* .center {
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
}
.ziji {
text-align: center;
line-height: 100px;
} */
/* 第二种:利用table—cell */
/* .center {
display: table-cell;
text-align: center;
vertical-align: middle;
}
.ziji {
display: inline-block;
} */
/* 垂直居中 */
/* .center {
display: flex;
justify-content: center;
align-items: center;
}
.ziji {} */
/* 垂直居中结束 */
/* 第三种:利用相对定位和绝对定位实现 */
/* .center {
position: relative;
}
.ziji {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
} */
/* 垂直水平居中 */
/* 第一中方法 */
/* .wrap {
width: 300px;
height: 300px;
background-color: #e3e3e3;
position: relative;
}
.box {
width: 100px;
height: 100px;
background-color: brown;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
} */
/* 第一中方式结束 */
/* 第二种方式开始 */
.wrap {
width: 300px;
height: 300px;
background-color: #e3e3e3;
display: flex;
justify-content: center;
align-items: center;
}
.box {
width: 100px;
height: 100px;
background-color: brown;
}
/* 第二种方式结束 */
/* 第三种方式开始 */
.wrap {
width: 300px;
height: 300px;
background-color: #e3e3e3;
display: table-cell;
vertical-align: middle;
}
.box {
width: 100px;
height: 100px;
background-color: brown;
margin: auto;
}
/* 第三种方式结束 */
</style>
</head>
<body>
<div class="wrap">
<div class="box"></div>
</div>
<!-- <div class="center">
<div class="ziji">
居中
</div>
</div> -->
<!-- <div class="zi">
盒子
</div>
<div class="fuji">
<div class="zi">
盒子
</div>
</div> -->
</body>
</html>
<div>
<p>relative:相对定位,相对于自己的定位,并没有脱离标准文档流</p>
<p>absolute:绝对定位:相对于自己最近的父级元素做定位(先找父元素,父元素如果没定位,继续向上寻找爷爷辈的元素,以此类推),脱离了标准的文档流</p>
<p>fixed:固定定位,相对于可视窗口的定位,脱离了标准的文档流</p>
<p>static:默认的定位,相当于没有定位</p>
</div>
1)伪类(pseudo-classes) <br> 其核⼼就是⽤来选择DOM树之外的信息,不能够被普通选择器选择的⽂档之外的元素,⽤来添加⼀些选择器的特殊效果。
<br> ⽐如:hover :active :visited :link :visited :first-child :focus :lang等<br> 由于状态的变化是⾮静态的,所以元素达到⼀个特定状态时,它可能得到⼀个伪类的样式;当状态改变时,它⼜会失去这个样式。
<br> 由此可以看出,它的功能和class有些类似,但它是基于⽂档之外的抽象,所以叫 伪类。<br> 2)伪元素(Pseudo-elements)
<br> DOM树没有定义的虚拟元素
<br> 核⼼就是需要创建通常不存在于⽂档中的元素,
<br> ⽐如::before ::after 它选择的是元素指定内容,表示选择元素内容的之前内容或之后内容。<br> 伪元素控制的内容和元素是没有差别的,但是它本身只是基于元素的抽象,并不存在于⽂档中,所以称为伪元素。⽤于将特殊的效果添加到某些选择 器
<br> 2)伪类与伪元素的区别
<br> 表示⽅法
<br> CSS2 中伪类、伪元素都是以单冒号:表示,<br> CSS2.1 后规定伪类⽤单冒号表示,伪元素⽤双冒号::表示,<br> 浏览器同样接受 CSS2 时代已经存在的伪元素(:before, :after, :first�line, :first-letter 等)的单冒号写法。<br> CSS2 之后所有新增的伪元素(如::selection),应该采⽤双冒号的写法。<br> CSS3中,伪类与伪元素在语法上也有所区别,伪元素修改为以::开头。浏览器对以:开头的伪元素也继续⽀持,但建议规范书写为::开头
<br> 定义不同
<br> 伪类即假的类,可以添加类来达到效果
<br> 伪元素即假元素,需要通过添加元素才能达到效果
<br> 总结:
<br> 伪类和伪元素都是⽤来表示⽂档树以外的"元素"。
<br> 伪类和伪元素分别⽤单冒号:和双冒号::来表示。
<br> 伪类和伪元素的区别,关键点在于如果没有伪元素(或伪类),
<br> 是否需要添加元素才能达到效果,如果是则是伪元素,反之则是伪类。
<br> 4)相同之处:
<br> 伪类和伪元素都不出现在源⽂件和DOM树中。也就是说在html源⽂件中是看不到伪类和伪元素的。
<br> 不同之处:
<br> 伪类其实就是基于普通DOM元素⽽产⽣的不同状态,他是DOM元素的某⼀特征。
<br> 伪元素能够创建在DOM树中不存在的抽象对象,⽽且这些抽象对象是能够访问到的。
<br>
<!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>Document</title>
<style>
.fulei {
width: 400px;
height: 400px;
background-color: #bfa;
position: relative;
margin: 0 auto;
}
.zilei {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
/* 锤子水平居中 */
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
/* margin-left: auto;
margin-right: auto; */
}
</style>
</head>
<body>
<div class="fulei">
<div class="zilei"></div>
</div>
</body>
</html>
/*
* all:所有设备
* print:打印设备
* speech:屏幕阅读器
* screen:带屏幕的设备
*
*/
/*表示只有屏幕可以使用(老版本的浏览器可以使用) @media only screen {
} */
/* 媒体查询的特性
width:视口的宽度
height:视口的高度
min-width:视口的最小宽度
max-width:视口的最大宽度
,:或者
and:和
not:除了
*/
@media only screen and (min-width:500px) and (max-width:780px) {
body {
background-color: orange;
}
}
@media (width:500px) {
body {
background-color: #bfa;
}
}
@media all {
body {
background-color: #bfa;
}
}
/*
flex-direction:弹性盒子中元素的排列方式
flex-shrink:收缩性(默认1)
flex-grow:伸展(1)
flex-wrap:wrap;//换行
flex-wrap:nowrap;//不换行
flex-flow: row wrap;//换行并且row排列
justify-content:flex-start//元素沿着排列的起边开始排列
justify-content:flex-end//元素沿着排列的主轴的终边排列
*/