HTML5全屏浏览器兼容方案

最近一个项目有页面全屏的的需求,搜索了下有HTML5的全屏API可用,不过各浏览器的支持不一样。

标准 webkit Firefox IE
Element.requestFullscreen() webkitRequestFullscreen mozRequestFullScreen msRequestFullscreen
Document.exitFullscreen() webkitExitFullscreen mozCancelFullScreen msExitFullscreen
Document.fullscreenElement webkitFullscreenElement mozFullScreenElement msFullscreenElement
Document.fullscreenEnabled webkitFullscreenEnabled mozFullScreenEnabled msFullscreenEnabled
Document.fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange
Document.fullscreenerror webkitfullscreenerror mozfullscreenerror MSFullscreenError

MDN Fullscreen API: The Fullscreen API provides an easy way for web content to be presented using the user's entire screen. The API lets you easily direct the browser to make an element and its children, if any, occupy the fullscreen, eliminating all browser user interface and other applications from the screen for the duration.

全屏接口提供了简单的方式通过用户整个屏幕展示浏览器的内容。这个接口让我们很轻松的引导浏览器使一个元素和它的子元素占据整个屏幕,并且从屏幕上消除所有浏览器用户界面和其它应用程序。

一、接口使用(以谷歌浏览器为例)

1.requestFullscreen()

全屏请求方法,使用方法:Element.requestFullscreen()

<div id="example">
    <img src="html5.png">
    <button type="button" id="requestFullscreen">requestFullscreen</button>
</div>

<script>
// 全屏
document.getElementById('requestFullscreen').addEventListener('click', () => {
    document.querySelector('img').webkitRequestFullscreen();
});
</script>

触发事件后会有按ESC即可退出全屏模式的文字提示。

注意

1.在< iframe >框架中使用全屏需要加allowfullscreen属性。
2.全屏请求只能通过用户操作触发,否则会出现Failed to execute 'requestFullscreen' on 'Element': API can only be initiated by a user gesture.这样的警告,解决办法是将此方法绑定到某个用户操作事件上,例如点击事件click

(function () {
    document.documentElement.webkitRequestFullscreen();
})();

2.exitFullscreen()

退出全屏模式的方法,使用方法:document.exitFullscreen(),除了requestFullscreen()其它方法和属性都是基于document的。

<div id="example">
    <img src="html5.png">
    <button type="button" id="requestFullscreen">requestFullscreen</button>
    <button type="button" id="exitFullscreen">exitFullscreen</button>
</div>

<script>
// 退出全屏
document.getElementById('exitFullscreen').addEventListener('click', () => {
    document.webkitExitFullscreen();
});
</script>

触发后退出全屏恢复页面原来的样子,也可以按ESC退出;另外F11也可以使页面全屏显示和退出,但这应该属于浏览器的功能,不在HTML5 API的范畴之内。

3.fullscreenElement

若是全屏模式下,显示全屏的元素,若不是,返回null

<div id="example">
    <img src="html5.png">
    <button type="button" id="requestFullscreen">requestFullscreen</button>
    <button type="button" id="exitFullscreen">exitFullscreen</button>
    <button type="button" id="fullscreenElement">fullscreenElement</button>
</div>

<script>
// 显示全屏元素
document.getElementById('fullscreenElement').addEventListener('click', () => {
    console.log(document.webkitFullscreenElement); // <div id=...></div> 或 null
});
</script>

4.fullscreenEnabled

返回一个布尔值true/false,判断是否可用全屏模式。

<div id="example">
    <img src="html5.png">
    <button type="button" id="fullscreenEnabled">fullscreenEnabled</button>
</div>

<script>
// 全屏是否可用
document.getElementById('fullscreenEnabled').addEventListener('click', () => {
    console.log(document.webkitFullscreenEnabled); // true
});
</script>

二、浏览器兼容

由于各主流浏览器调用全屏接口的方法不一致,所以调用之前需要判断一下当前浏览器适用的方法。

我简单的做了下请求全屏退出全屏的适配。

const MAZEY_FULL_SCREEN = function () {
    let prefixArr = ['', 'webkit', 'moz', 'ms'], // 浏览器前缀
        isRightRequest, // 是否找到适配的方法
        isRightExit,
        requestMethod, // 全屏方法
        exitMethod, // 退出全屏方法
        lowerFirst = function (str) {
            return str.slice(0, 1).toLowerCase() + str.slice(1);
        },
        requestSuffixArr = ['RequestFullscreen', 'RequestFullScreen'], // 后缀
        exitSuffixArr = ['ExitFullscreen', 'CancelFullScreen'],
        searchRightMethod = function (prefix, suffixArr, documentParent) {
            let methodArr = suffixArr.map((suffix) => {
                return prefix + suffix;
            }),
            method,
            isRight;
            methodArr.forEach((wholePrefix) => {
                if (isRight) return;
                if (prefix.length === 0) {
                    wholePrefix = lowerFirst(wholePrefix)
                }
                if (wholePrefix in documentParent) {
                    method = wholePrefix;
                    isRight = true;
                    // console.log(method);
                }
            });
            return method;
        };
    prefixArr.forEach((prefix) => {
        if (isRightRequest && isRightExit) return;
        // 查找请求
        requestMethod = searchRightMethod(prefix, requestSuffixArr, document.documentElement);
        isRightRequest = Boolean(requestMethod);
        // 查找退出
        exitMethod = searchRightMethod(prefix, exitSuffixArr, document);
        isRightExit = Boolean(exitMethod);
    });
    this.request = function (element) {
        let domEle = document.querySelector(element) || document.documentElement;
        domEle[requestMethod]();
    };
    this.exit = function () {
        document[exitMethod]();
    };
};

let fullscreen = new MAZEY_FULL_SCREEN();

使用示例:

<h1 id="h1">html5 - 全屏</h1>
<button id="request">请求</button>
<button id="exit">退出</button>
<script src="mazey-full-screen.js"></script>

<script>
// 请求全屏
document.getElementById('request').addEventListener('click', () => {
    fullscreen.request();
});
// 退出全屏
document.getElementById('exit').addEventListener('click', () => {
    fullscreen.exit();
});
</script>

示例代码:GitHub

JavaScript中typeof,instanceof,hasOwnProperty,in的用法和区别

一. typeof操作符

typeof操作符用于返回正在使用值的类型。

// 使用原始值
let mNull = null;
let mUndefined = undefined;
let mString = 'mazey';
let mNumber = 123;
let mBoolean = true;
let mFunction = function () {
    return true;
};

// 用构造函数的方式new一个实例
let oString = new String('cherrie');
let oRegExp = new RegExp('^[0-9]+$');
let oFunction = new Function('x', 'y', 'return x + y');

let oObj = {};
let oNew = new Object();

// typeof值
console.log(typeof mNull); // object
console.log(typeof mUndefined); // undefined
console.log(typeof mString); // string
console.log(typeof mNumber); // number
console.log(typeof mBoolean); // boolean
console.log(typeof mFunction); // function
console.log(typeof oString); // object
console.log(typeof oRegExp); // object
console.log(typeof oFunction); // function
console.log(typeof oObj); // object
console.log(typeof oNew); // object

在《JavaScript启示录》中new RegExp()介绍会返回function,但是事实上我在chrome控制台中看到的是object

于是我console.log(new RegExp('^[0-9]+$')),打印出来的是字符串/^[0-9]+$/

console.log(new RegExp('^[0-9]+$')); // /^[0-9]+$/
console.log(RegExp); // ƒ RegExp() { [native code] } 原始值
console.log(String); // ƒ String() { [native code] } 原始值
console.log(/^[0-9]+$/); // /^[0-9]+$/
console.log(new RegExp('^[0-9]+$') === /^[0-9]+$/); // false
console.log(RegExp('^[0-9]+$') === /^[0-9]+$/); // false

综上可以看出现版本RegExpString Number一样属于JavaScript的原始值。

Math作为JavaScript中的静态对象回返回什么呢?

console.log(typeof Math); // object
console.log(typeof Math.PI); // number
console.log(typeof Math.ceil); // function

所以Math__proto__还是Objecttypeof还能返回对象的属性和方法的类型。

typeof使用场景

1.判断某个变量是否已定义

console.log(typeof aaa); // 'undefined'

// 判断
if (typeof bbb === 'undefined') {
    console.log('变量未定义');
}

2.区分原始值和复杂值(对象值)

因为复杂值往往返回object,当然有个例外就是原始值里面的null也返回object,然后function作为Object的实例也是复杂值。

// 判断是否时复杂值(对象值)
function isObject (m) {
    return (typeof m === 'function' || (typeof m === 'object' && m !== null));
}

console.log(isObject(new RegExp('123'))); // true
console.log(isObject('123')); // false
console.log(isObject(String('123'))); // false
console.log(isObject(null)); // false

// 判断是否是原始值
function isNative (m) {
    return (m === null || (typeof m !== 'object' && typeof m !== 'function'));
}

console.log(isNative(new RegExp('123'))); // false
console.log(isNative('123')); // true
console.log(isNative(String('123'))); // true
console.log(isNative(null)); // true

3.检测某个变量是否是函数

当使用闭包时判断是函数后再进行下一步。

function qqq () {
    let a = 0;
    let b = function () {
        a++;
        console.log(a);
    };
    return b;
}

let ccc = qqq();
console.log(typeof ccc); // function
if (typeof ccc === 'function') {
    ccc(); // 1
    ccc(); // 2
    ccc(); // 3
    ccc(); // 4
}

二. instanceof操作符

通过使用instanceof操作符,可以确定一个对象是否是特定构造函数实例,返回truefalse

instanceof只适用于构造函数创建返回的复杂对象实例

任何时间判断一个对象(复杂值)是否是Object的实例时,它都将返回true,因为所有对象都继承自Object()构造函数。

let oFather = function () {
    this.firstName = 'mazey';
};
oFather.prototype.lastName = 'qian';

// 实例
let oSon = new oFather();
console.log(oSon instanceof oFather); // true

// 继承
let nFather = function () {};
nFather.prototype = new oFather();
nFather.construction = nFather;
console.log(nFather.firstName); // undefined
console.log(nFather.prototype.lastName); // qian
console.log(nFather instanceof oFather); // false
console.log(new nFather() instanceof nFather); // true

// 相对于Object来说
console.log('123' instanceof Object); // false
console.log(new String('123') instanceof Object); // true 构造出来的实例
console.log(null instanceof Object); // false

instanceof使用场景

判断在一个继承关系中实例是否属于它的父类。

// 继承
let oFather = function () {};
let nFather = function () {};
nFather.prototype = new oFather();
nFather.construction = nFather;

let nSon = new nFather();
console.log(nSon instanceof nFather); // true
console.log(nSon instanceof oFather); // true

三. in操作符和hasOwnProperty方法

in操作符可以检查一个对象的属性,包括来自原型链的属性,hasOwnProperty()方法可以检查来自非原型链属性的对象。

例如现在有一个对象let obj = {name: 'mazey'};name是它自身定义的属性,toString是它从原型链上继承下来的属性。

let obj = {name: 'mazey'};
console.log('name' in obj); // true
console.log('toString' in obj); // true
console.log('name' in Object); // true
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('toString')); // false
console.log(Object.hasOwnProperty('name')); // true

所以in操作符查找的范围更广一点,可以用hasOwnProperty()判断是否是对象自身的属性,而不是通过类似obj.prototype.foo = 'foo';这样定义的。

hasOwnProperty方法使用场景

在实际项目中经常使用for...in...来遍历对象中可枚举的属性,但是for...in...常常把原型obj.prototype.xxx中的属性也列举出来,所以在循环的时候可以加上hasOwnProperty()方法判断下。

function obj0 () {
    this.name = 'mazey',
    this.age = '24'
};
obj0.prototype.gender = 'male';
let obj1 = new obj0();

// 打印所有可枚举属性
for (let key in obj1) {
    console.log(key); // name age gender 从原型链上继承下来的属性也会被打印出来
}

// 过滤掉原型链上的属性
for (let key in obj1) {
    if (obj1.hasOwnProperty(key)) {
        console.log(key); // name age
    }
}

四. 总结

1.typeof可以判断使用值的类型,注意null返回object
2.instanceof验证构造函数构造出来的实例,可以用来判断一个对象是否属于一个父类。
3.hasOwnProperty方法常常与in操作符搭配使用,用来遍历一个对象自身的属性。

五. 相关扩展

1.删除对象的属性

若想把一个对象的自身属性完全删除,要使用delete操作符。

let obj0 = {
    name: 'mazey',
    age: 24
};

// 删除age属性
delete obj0.age;
console.log(obj0.hasOwnProperty('age')); // false
console.log('age' in obj0); // false

// 试着删除原型链上的属性 toString
delete obj0.toString
console.log('toString' in obj0); // true

需要注意的是delete不会删除原型链上的属性。

2.可枚举

每个对象的属性都分为可枚举和不可枚举属性,可以使用propertyIsEnumerable()方法来检查哪些属性是可枚举的。

每个对象都有一个propertyIsEnumerable方法。此方法可以确定对象中指定的属性是否可以被for...in(for…in语句以任意顺序遍历一个对象的可枚举属性。对于每个不同的属性,语句都会被执行)循环枚举,但是通过原型链继承的属性除外。如果对象没有指定的属性,则此方法返回false

有的资料说只要能被for..in遍历的属性就是可枚举的,实际上要排除从原型链上继承下来的属性,只有自身的属性是可枚举的。

// 第一个构造函数
function ConFun0 () {
    this.firstName = 'mazey';
}
ConFun0.prototype.firstCom = 'bang';

// 第二个构造函数
function ConFun1 () {
    this.secondName = 'qian';
}
// 继承第一个
ConFun1.prototype = new ConFun0();
ConFun1.prototype.constructor = ConFun1;

// 实例
let obj = new ConFun1();
obj.girlName = 'cherrie';

// 是否可枚举
console.log(obj.propertyIsEnumerable('constructor')); // false
console.log(obj.propertyIsEnumerable('firstName')); // false
console.log(obj.propertyIsEnumerable('firstCom')); // false
// 通过原型链继承的属性不是可枚举
console.log(obj.propertyIsEnumerable('secondName')); // true
console.log(obj.propertyIsEnumerable('girlName')); // true

for (let key in obj) {
    console.log(key); // secondName girlName (原型链上的属性也会被打印出来->) firstName constructor firstCom
}

console.log(`---分割线---`);

for (let key in obj) {
    // 过滤掉原型链上的属性
    if (obj.hasOwnProperty(key)) {
        console.log(key); // secondName girlName
    }
}

所以可枚举的属性一定能被for..in循环遍历出来,但是for...in循环遍历出来的属性不一定是可枚举的,需排除从原型链上继承下来的属性,这里可以通过hasOwnProperty()方法过滤掉不可枚举属性。

vue+vuex+axios+echarts画一个动态更新的中国地图

一. 生成项目及安装插件

# 安装vue-cli
npm install vue-cli -g

# 初始化项目
vue init webpack china-map

# 切到目录下
cd china-map

# 安装项目依赖
npm install

# 安装 vuex
npm install vuex --save

# 安装 axios
npm install axios --save

# 安装 ECharts
npm install echarts --save

二. 项目结构

├── index.html
├── main.js
├── components
│   └── index.vue
└── store
    ├── index.js          # 组装模块及导出store的文件
    └── modules
        └── ChinaMap.js   # 中国地图Vuex模块

三. 引入中国地图并绘制基本的图表

1.按需求引入与中国地图相关的Echarts图表和组。

// 主模块
let echarts = require('echarts/lib/echarts')
// 散点图
require('echarts/lib/chart/scatter')
// 散点图放大
require('echarts/lib/chart/effectScatter')
// 地图
require('echarts/lib/chart/map')
// 图例
require('echarts/lib/component/legend')
// 提示框
require('echarts/lib/component/tooltip')
// 地图geo
require('echarts/lib/component/geo')

2.引入中国地图JS文件,会自动注册地图;也可以通过axios方式引入json文件,需要手动注册echarts.registerMap('china', chinaJson.data)

// 中国地图JS文件
require('echarts/map/js/china')

3.准备一个有固定宽高的DOM容器并在mounted里面初始化一个echarts实例。

DOM容器

<template>
  <div id="china-map"></div>
</template>

初始化echarts实例

let chinaMap = echarts.init(document.getElementById('china-map'))

4.设置初始化的空白地图,这里需要设置很多echarts参数,参考ECharts配置项手册

chinaMap.setOption({
    backgroundColor: '#272D3A',
    // 标题
    title: {
      text: '中国地图闪闪发光',
      left: 'center',
      textStyle: {
        color: '#fff'
      }
    },
    // 地图上圆点的提示
    tooltip: {
      trigger: 'item',
      formatter: function (params) {
        return params.name + ' : ' + params.value[2]
      }
    },
    // 图例按钮 点击可选择哪些不显示
    legend: {
      orient: 'vertical',
      left: 'left',
      top: 'bottom',
      data: ['地区热度', 'top5'],
      textStyle: {
        color: '#fff'
      }
    },
    // 地理坐标系组件
    geo: {
      map: 'china',
      label: {
        // true会显示城市名
        emphasis: {
          show: false
        }
      },
      itemStyle: {
        // 地图背景色
        normal: {
          areaColor: '#465471',
          borderColor: '#282F3C'
        },
        // 悬浮时
        emphasis: {
          areaColor: '#8796B4'
        }
      }
    },
    // 系列列表
    series: [
      {
        name: '地区热度',
        // 表的类型 这里是散点
        type: 'scatter',
        // 使用地理坐标系,通过 geoIndex 指定相应的地理坐标系组件
        coordinateSystem: 'geo',
        data: [],
        // 标记的大小
        symbolSize: 12,
        // 鼠标悬浮的时候在圆点上显示数值
        label: {
          normal: {
            show: false
          },
          emphasis: {
            show: false
          }
        },
        itemStyle: {
          normal: {
            color: '#ddb926'
          },
          // 鼠标悬浮的时候圆点样式变化
          emphasis: {
            borderColor: '#fff',
            borderWidth: 1
          }
        }
      },
      {
        name: 'top5',
        // 表的类型 这里是散点
        type: 'effectScatter',
        // 使用地理坐标系,通过 geoIndex 指定相应的地理坐标系组件
        coordinateSystem: 'geo',
        data: [],
        // 标记的大小
        symbolSize: 12,
        showEffectOn: 'render',
        rippleEffect: {
          brushType: 'stroke'
        },
        hoverAnimation: true,
        label: {
          normal: {
            show: false
          }
        },
        itemStyle: {
          normal: {
            color: '#f4e925',
            shadowBlur: 10,
            shadowColor: '#333'
          }
        },
        zlevel: 1
      }
    ]
  })

四. 配置Vuex管理和分发数据

1.在ChinaMap.js中引入vuex和axios。

import axios from 'axios'

2.设置必要的变量。

const state = {
  geoCoordMap: {'香港特别行政区': [114.08, 22.2], '澳门特别行政区': [113.33, 22.13], '台北': [121.5, 25.03]/*等等*/},
  // 发光的城市
  showCityNumber: 5,
  showCount: 0,
  // 是否需要loading
  isLoading: true
}

3.在actions中抓取后台数据并更新地图。

const actions = {
  fetchHeatChinaRealData ({state, commit}, chartsObj) {
    axios.get('static/data/heatChinaRealData.json')
      .then(
        (res) => {
          let data = res.data
          let paleData = ((state, data) => {
            let arr = []
            let len = data.length
            while (len--) {
              let geoCoord = state.geoCoordMap[data[len].name]
              if (geoCoord) {
                arr.push({
                  name: data[len].name,
                  value: geoCoord.concat(data[len].value)
                })
              }
            }
            return arr
          })(state, data)
          let lightData = paleData.sort((a, b) => {
            return b.value - a.value
          }).slice(0, state.showCityNumber)
          chartsObj.setOption({
            series: [
              {
                name: '地区热度',
                data: paleData
              },
              {
                name: 'top5',
                data: lightData
              }
            ]
          })
        }
      )
  }
}

此时npm run dev已经可以看到中国地图上闪闪的黄色小点点。
若想改变她使动态展示,可以在index.vue中mounted下面加上:

chinaMap.showLoading(showLoadingDefault)
this.$store.commit('openLoading')
this.$store.dispatch('fetchHeatChinaRealData', chinaMap)
setInterval(() => {
    this.$store.dispatch('fetchHeatChinaRealData', chinaMap)
}, 1000)

在ChinaMap.js中actions的mutations中fetchHeatChinaRealData修改:

let lightData = paleData.sort((a, b) => {
    return b.value - a.value
}).slice(0 + state.showCount, state.showCityNumber + state.showCount)
if (state.isLoading) {
    chartsObj.hideLoading()
    commit('closeLoading')
}

五. 其它

1.别忘了在main.js里面引入Vuex。

import Vue from 'vue'
import Index from './components/index.vue'
import store from './store/index'

let ChinaMap = new Vue({
  el: '#app',
  store,
  template: '<Index/>',
  components: {Index}
})

Vue.use(ChinaMap)

2.案例代码

GitHub

JavaScript深入理解sort()方法

一. 基本用法

let arr1 = [3, 5, 7, 1, 8, 7, 10, 20, 19]
console.log(arr1.sort())
// [1, 10, 19, 20, 3, 5, 7, 7, 8]

如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。

其实,在使用sort()进行排序的时候会调用toString()函数将其值转换成字符串在进行比较,是按ASCII进行比较的。

于是,在比较数字时会转换成字符串再比较,结果就会不准确。

二. 改进用法

let arr1 = [3, 5, 7, 1, 8, 7, 10, 20, 19]
console.log(arr1.sort(function (a, b) {
    if (a < b) {
        return -1
    }
    if (a > b) {
        return 1
    }
    return 0
}))
// [1, 3, 5, 7, 7, 8, 10, 19, 20]
console.log(arr1.sort(function (a, b) {
    return a - b
}))
// [1, 3, 5, 7, 7, 8, 10, 19, 20]

sort()同时也是一个高阶函数,里面可以放一个比较函数:arr.sort(compareFunction)

arr.sort(function (a, b) {
    return ?
})
  • 若compareFunction返回值小于0,a排在b前面,即a与b的位置不变。
  • 若compareFunction返回值等于0,a与b的位置不变。
  • 若compareFunction返回值大于0,a排在b的后面,即a与b的位置交换。

即若返回值大于0的时候交换a与b的位置,其他情况位置不变。

  • 升序:return a – b
  • 降序:return b – a
// 降序示例
let arr1 = [3, 5, 7, 1, 8, 7, 10, 20, 19]
console.log(arr1.sort(function (a, b) {
    return b - a
}))
// [20, 19, 10, 8, 7, 7, 5, 3, 1]
console.log(arr1.sort((a, b) => {
    return b - a
}))
// [20, 19, 10, 8, 7, 7, 5, 3, 1]

三. 比较数组中的对象

let arr2 = [
    {
        name: 'mazey0',
        value: 3
    },
    {
        name: 'mazey1',
        value: 5
    },
    {
        name: 'mazey2',
        value: 7
    },
    {
        name: 'mazey3',
        value: 1
    },
    {
        name: 'mazey4',
        value: 10
    },
    {
        name: 'mazey5',
        value: 7
    }
]
// 升序
let arr3 = arr2.sort((a, b) => {
    return a.value - b.value
})
arr3.forEach((value, index, arr) => {
    console.log(value.value)
})
// 1 3 5 7 7 10

CSS3 Flex布局(项目)

一、order属性

order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

二、flex-grow属性

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

三、flex-shrink属性

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。负值对该属性无效。

四、flex-basis属性

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。

五、flex属性

flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

六、align-self属性

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

Flex 布局教程:语法篇

CSS3 Flex布局(容器)

一、flex-direction属性

  • row(默认值):主轴为水平方向,起点在左端。
  • row-reverse:主轴为水平方向,起点在右端。
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。
<style>
.box{
    background: #0074D9;
    display: flex;
    flex-direction: row-reverse;
}
.box>div[class^="item"]{
    color: #FFFFFF;
}
</style>

<div class="box">
    <div class="item1">item1</div>
    <div class="item2">item2</div>
    <div class="item3">item3</div>
    <div class="item4">item4</div>
    <div class="item5">item5</div>
</div>

二、flex-wrap属性

  • nowrap(默认):不换行。
  • wrap:换行,第一行在上方。
  • wrap-reverse:换行,第一行在下方。

三、flex-flow属性

flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。

四、justify-content属性

justify-content属性定义了项目在主轴上的对齐方式。

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

五、align-items属性

align-items属性定义项目在交叉轴上如何对齐。

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

垂直居中

<style>
.box{
    background: #0074D9;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 500px;
    height: 500px;
}
.box>div[class^="item"]{
    color: #FFFFFF;
}
</style>

<div class="box">
    <div class="item1">item1</div>
    <div class="item2">item2</div>
    <div class="item3">item3</div>
    <div class="item4">item4</div>
    <div class="item5">item5</div>
</div>

六、align-content属性

align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

Flex 布局教程:语法篇

JavaScript正则中\1\2的作用

一、示例

1. 验证6个相同的数字

var reg = new RegExp(/^(\d)\1{5}/g);
var a = '333333';
if(reg.test(a)) {
    alert('right');
} else {
    alert('wrong');
}

2. 验证3个相同的数字+3个相同的字母

var reg = new RegExp(/^(\d)\1{2}([a-z])\2{2}/g);
var a = '333aa1';
if(reg.test(a)) {
    alert('right');
} else {
    alert('wrong');
}

二、解释:

\1必须与小括号配合使用。

正则表达式中的小括号”()”。是代表分组的意思。 如果再其后面出现\1则是代表与第一个小括号中要匹配的内容相同。Link

原生JavaScript写AJAX

前端JavaScript:

function ajaxGet(url, obj) {
    var request;
    if(window.XMLHttpRequest) {
        request = new XMLHttpRequest();
    } else {
        request = new ActiveXObject('Microsoft.XMLHTTP'); // 兼容IE
    }

    request.onreadystatechange = function() {
        if(request.readyState === 4) { // 4 请求完成
            if(request.status === 200) { // 200 页面成功加载
                console.log(request.responseText); // 成功 返回得到的文本
            } else {
                console.log(request.status); // 失败 返回状态码 如 404
            }
        } else {
            console.log('Requesting');
        }
    }
    /* 解析参数 */
    str = '?';
    for(key in obj) {
        str += (key + '=' + obj[key] + '&');
    }
    str = str.substr(0, str.length - 1);
    /* 发送 */
    request.open('GET', url + str);
    request.send();
}

ajaxGet('ajax.php', {
    'type': 'get',
    'data': 'test'
}); //get-test

后端PHP:

<!-- ajax.php -->
<?php
    echo $_GET['type'] . '-' . $_GET['data'];

Linux彻底删除mysql5.6

查看安装的mysql组件

rpm -qa | grep -i mysql

mysql57-community-release-el6-8.noarch
mysql-community-common-5.6.37-2.el6.x86_64
mysql-community-client-5.6.37-2.el6.x86_64
php70w-mysql-7.0.22-2.w6.x86_64
mysql-community-libs-5.6.37-2.el6.x86_64
mysql-community-libs-compat-5.6.37-2.el6.x86_64
mysql-community-server-5.6.37-2.el6.x86_64

查看与mysql相关的文件

find / -name mysql

/home/mysql
/etc/logrotate.d/mysql
/usr/share/mysql
/usr/bin/mysql
/usr/lib64/mysql
/var/spool/mail/mysql
/var/lib/mysql
/var/lib/mysql/mysql

whereis mysql

mysql: /usr/bin/mysql /usr/lib64/mysql /usr/share/mysql /usr/share/man/man1/mysql.1.gz

卸载mysql组件

rpm -ev --nodeps mysql57-community-release-el6-8.noarch
rpm -ev --nodeps mysql-community-common-5.6.37-2.el6.x86_64
rpm -ev --nodeps mysql-community-client-5.6.37-2.el6.x86_64
rpm -ev --nodeps mysql-community-libs-5.6.37-2.el6.x86_64
rpm -ev --nodeps mysql-community-libs-compat-5.6.37-2.el6.x86_64
rpm -ev --nodeps mysql-community-server-5.6.37-2.el6.x86_64

删除mysql相关文件

rm -rf /home/mysql
rm -rf /etc/logrotate.d/mysql
rm -rf /usr/share/mysql
rm -rf /usr/bin/mysql
rm -rf /usr/lib64/mysql
rm -rf /var/spool/mail/mysql
rm -rf /var/lib/mysql
rm -rf /var/lib/mysql/mysql

Linux问题: SSH FTP登录不了

昨天准备新加一个FTP用户来管理/etc下面的文件。然后执行chmod 777 -R /etc后出现了一系列的崩溃,服务器登不上,有些文件变成了只读,FTP和PUTTY登录不上。

之后尝试了git传文件被拒绝。

搜索了问题后无果,想到自己是新加FTP出现的问题,会不会是权限的问题?于是搜索了更改/etc权限会出现的问题,果不其然,会影响SSH的登录。没有备份的情况下只能重装系统。

因为我的一系列Nginx重定向规则不能下载,只能重装后再手打了。:(