首页

数组常用的方法

seo达人

数组常见方法

数组的方法

一、join() 方法 ----->不会改变原数组

二、concat() 方法 ----->不会改变原数组

三、splice(index, num, item) ----->会改变原数组

  1. splice(index, num) 删除功能
  2. splice(index, 0, ...item)
  3. splice(index, num, item)
  4. splice(index)

    四、slice() -----> 不会改变原数组

    五、push() 和 pop() ----->会改变原数组

    六、shift() 和 unshift() -----> 会改变原数组

    七、sort() -----> 会改变原数组

    八、reverse() ----->会改变原数组

    九、indexOf() 和 lastIndexOf()

    十、includes()

    十一、forEach()

    十二、map() -----> 不会改变原数组

    十三、filter() -----> 不会改变原数组

    十四、every()

    十五、some()

    十六、reduce() 和 reduceRight()

    十七、Array.from() 将类数组转化为数组

    十八、Array.of() 方法用于将一组值转化为数组

    十九、数组实例的 find() 和 findIndex()

    二十、扁平化数组 flat() 方法 -----> 不会改变原数组

    数组的方法

    一、join() 方法 ----->不会改变原数组

    该方法可以将数组里面的元素,通过指定的分隔符以字符串的形式连接起来

    返回值:返回新的字符串



    // join() 将数组转化为字符串

    let arr = [1, 2, 3, 4, 5]

    let str1 = arr.join('|')

    console.log(arr) // [1, 2, 3, 4, 5]

    console.log(str1) // 1|2|3|4|5

    // 当传空字符串时

    let str2 = arr.join('') // 12345

    // 当不传时

    let str3 = arr.join() // 1,2,3,4,5

    1

    2

    3

    4

    5

    6

    7

    8

    9

    二、concat() 方法 ----->不会改变原数组

    该方法可以把两个数组里的元素拼接成一个新的数组

    返回值:返回拼接后的新数组



    let arr1 = [0, 1, 2]

    let arr2 = [2, 3, 4]

    let arr = arr1.concat(arr2)

    // 传入二维数组

    let arrCopy = arr1.concat([12, [17, 26]])

    console.log(arrCopy) // [0, 1, 2, 12, [17, 26]]

    console.log(arr) // [0, 1, 2, 2, 3, 4]

    console.log(arr1) // [0, 1, 2]

    console.log(arr2) // [2, 3, 4]



    // ES6 扩展运算符

    let a = [1, 2]

    let b = [2, 3]

    let ab = [...a, ...b] // [1, 2, 2, 3]

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    三、splice(index, num, item) ----->会改变原数组

    index 参数:必传,整数,规定添加或者删除的位置,使用负数时,从数组尾部规定位置

    num 参数:必传,要删除的数量,如果为 0,则不删除项目

    item 参数:可选参数,可以是多个,想数组添加的新项目

    splice 具有删除,插入,替换的功能


  5. splice(index, num) 删除功能

    index 参数:开始位置的索引



    num 参数:要删除元素的个数



    返回值:返回的是包含被删除元素的数组对象



    // 删除功能

    let array = [1, 2, 3, 4, 5]

    let newArr = array.splice(2, 2)

    console.log(newArr) // [1, 2, 5]

    console.log(array) // [3, 4]



    1

    2

    3

    4

    5

    6
  6. splice(index, 0, …item)

    index 参数:插入元素的索引值

    0 参数:不删除

    // 插入功能

    let arr = ['a', 'b', 'c', 'd', 'e']

    let newArr = arr.splice(1, 0, ['插入', 1217])

    console.log(newArr) // []

    console.log(arr) // ['a', ['插入', 1217], 'b', 'c', 'd', 'e']



    1

    2

    3

    4

    5

    6
  7. splice(index, num, item)

    index 参数:开始的索引位置

    num 参数:删除的项个数

    item 参数:替换项

    返回值:返回包含被删除的元素的数组对象

    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.splice(2, 2, '替换', '1226')

    console.log(newArr) // [3, 4]

    console.log(arr) // [1, 2, '替换', '1226', 5]



    1

    2

    3

    4

    5
  8. splice(index)

    当只传一个值时,表示从传入的 index 索引值开始截取到最后

    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.splice(3)

    console.log(newArr) // [4, 5]

    console.log(arr) // [1, 2, 3]

    1

    2

    3

    4

    四、slice() -----> 不会改变原数组

    返回从原数组中指定开始下标到结束下标之间的项组成的新数组

    slice() 方法可以接受一或两个参数,即要返回项的起始位置和结束位置

    array.slice(2) 若只设置一个参数,起始位置为2(包含下标2)开始到数组最后

    array.slice(2, 5) 若设置两个参数,起始下标为2(包含下标2)到结束下标5(不包含下标5)的数组

    当 slice() 参数中有负数时,将负数加上数组的长度值来替换该位置的数

    let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]

    let copyArr1 = arr.slice(2) // [3, 4, 5, 6, 7, 8, 9]

    let copyArr2 = arr.slice(2, 5) // [3, 4, 5] 

    let copyArr3 = arr.slice(-2) // [8, 9]

    let copyArr4 = arr.slice(2, -2) // [3, 4, 5, 6, 7]

    let copyArr5 = arr.slice(-2, -5) // []

    let copyArr6 = arr.slice(-5, -2) // [5, 6, 7]

    console.log(arr) // [1, 2, 3, 4, 5, 6, 7, 8, 9]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    五、push() 和 pop() ----->会改变原数组

    push() 可以接受任意数量的参数,将其逐个添加到数组的末尾,并返回修改后数组的长度(改变了原数组)

    pop() 删掉数组末尾最后一项,改变了数组的 length 值,并返回删除的项

    let arr = [1, 2, 3, 4, 5]

    let count = arr.push(0, 1217)

    console.log(count) // 7

    console.loh(arr) // [1, 2, 3, 4, 5, 0, 1217]



    let item = arr.pop()

    console.log(item) // 1217

    console.log(arr) // [1, 2, 3, 4, 5, 0]

    1

    2

    3

    4

    5

    6

    7

    8

    六、shift() 和 unshift() -----> 会改变原数组

    shift() 删除原数组的第一项,并返回删除元素的值,如果数组为空折返回 undefined

    unshift() 将参数添加到原数组的开头,并返回数组的长度

    let arr = [1, 2, 3, 4, 5]

    let item = arr.shift()

    console.log(item) // 1

    console.log(arr) // [2, 3, 4, 5]



    let count = arr.unshift(0, 'Jack')

    console.log(count) // 6

    console.log(arr) // [0, 'Jack', 2, 3, 4, 5]

    1

    2

    3

    4

    5

    6

    7

    8

    七、sort() -----> 会改变原数组

    在排序时,sort() 方法会调用每个数组项的 toString() 转型方法,然后比较得到的字符串,已确定如何排序,其本质是比较字符串的 ASCII 编码

    即使数组中的每一项都是数值,sort() 方法比较的也是字符串,因此会出现以下情况:

    let arr1 = ['a', 'd', 'e', 'b', 'c']

    console.log(arr1.sort()) // ['a', 'b', 'c', 'd', 'e']



    let arr2 = [12, 26, 3, 99, 52]

    console.log(arr2.sort()) // [12, 26, 3, 52, 99]



    1

    2

    3

    4

    5

    6

    解决办法



    let arr3 = [12, 26, 3, 99, 52]

    arr3.sort((a, b) => {

    return a -b

    })

    console.log(arr3) // [3, 12, 26, 52, 99]

    1

    2

    3

    4

    5

    冒泡排序(优化版)



    function mySort (arr) {

    let count = 0 // 记录循环次数

    // 外层循环  控制循环的次数,每次找到最大值

    for (let i = 0; i < arr.length - 1; i++) {

    count++

    // 判断是否排序好了

    let isSort = true // 初始值默认已经排序好了

    for (let j = 0; j < arr.length - 1 - i; j++) {

    count++

    if (arr[j] > arr[j + 1]) {

    isSort = false

    // 交换位置

    let tmp = arr[j]

    arr[j] = arr[j + 1]

    arr[j + 1] = tmp

    }

    }

    // 某一趟结束,判断一下是否结束

    // 如何判断是否排序好,根据是否发生了位置交换,如果发生了位置交换就说明没有排序好

    if (isSort) {

    break

    }

    }

    console.log(count)

    return arr

    }

    mySort([12, 26, 17, 520, 99])



    // 打印结果:count 9

    // arr [12, 17, 26, 99, 520]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    八、reverse() ----->会改变原数组

    反转数组项的顺序

    let arr = [1, 2, 3, 4, 5]

    arr.reverse()

    console.log(arr) // [5, 4, 3, 2, 1]



    1

    2

    3

    4

    九、indexOf() 和 lastIndexOf()

    indexOf() 接受两个参数:要查找的项和查找起点位置的索引(可选项),其中从数组的开头开始向后查找

    lastIndexOf() 接受两个参数:要查找的项和查找起点位置的索引(可选项),其中是从数组的末尾开始向前查找

    返回值:当存在时,返回要查找的项在数组中首次出现的索引值;当不存在时,返回 -1

    可以用来判断一个值是否存在数组中



    let arr = [1, 2, 3, 5, 7, 7, 8, 5, 12, 17]

    console.log(arr.indexOf(5)) // 3

    console.log(arr.lastIndexOf(5)) // 7



    console.log(arr.indexOf(5, 2)) // 3

    console.log(arr.lastIndexOf(5, 4)) // 3



    console.log(arr.indexOf('5')) // -1

    1

    2

    3

    4

    5

    6

    7

    8

    十、includes()

    Array.prototype.includes() 数组实例的方法

    返回一个布尔值,表示某个数组是否包含给定的值

    推荐使用:可以用来判断一个值是否存在数组中



    let arr = [1, 2, 3, 4, 5]

    console.log(arr.includes(3)) // true

    console.log(arr.includes(0)) // false

    1

    2

    3

    十一、forEach()

    对数组进行遍历,对数组中的每一项运行给定函数,没有返回值



    forEarch(function (item, index, array) {})



    参数 item:表示数组中的每一项

    参数 index:表示数组中每一项对应的索引值

    参数 array:表示数组本身

    let arr = [1, 2, 3, 4, 5]

    arr.forEach((item, index, array) => {

    console.log(item + '---' + index + '---' + (arr === array))

    })

    1

    2

    3

    4

    十二、map() -----> 不会改变原数组

    map() 方法是将数组中的每一项调用提供的函数,结果返回一个新数组,并没有改变原来的数组

    映射



    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.map(item => item * item)



    console.log(newArr) // [1, 4, 9, 16, 25]

    console.log(arr) // [1, 2, 3, 4, 5]

    1

    2

    3

    4

    5

    十三、filter() -----> 不会改变原数组

    filter() 方法是将数组中所有的元素进行判断,将满足条件的元素作为一个新数组返回

    过滤



    let arr = [12, 17, 26, 520, 1314]

    let newArr = arr.filter((item, index) => {

    return item > 20

    })

    console.log(newArr) // [26, 520, 1314]

    1

    2

    3

    4

    5

    十四、every()

    every() 判断数组中每一项都是否满足条件,只有所有项都满足条件才返回 true,否则返回 false

    let arr = [1, 2, 3, 4, 5]

    let boolean1 = arr.every(item => item > 0)

    let boolean2 = arr.every(item => item > 3)



    console.log(boolean1) // true

    console.log(boolean2) // false

    1

    2

    3

    4

    5

    6

    十五、some()

    some() 判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回 true,否则返回 false

    let arr = [1, 2, 3, 4, 5]

    let boolean3 = arr.some(item => item > 3)

    let boolean4 = arr.some(item => item < 0)



    console.log(boolean3) // true

    console.log(boolean4) // false

    1

    2

    3

    4

    5

    6

    十六、reduce() 和 reduceRight()

    reduce() 方法是所有元素调用返回函数,返回值为最后结果,传入的值必须是函数类型

    接受两个参数:每一项调用的函数和作为归并基础的初始值(可选项)

    这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。



    // 利用 reduce() 方法实现数组求和,给数组一开始家里一个初始值 3

    let arr = [1, 2, 3, 4, 5]

    let sum = arr.reduce((prev, cur, index, array) => {

    // 函数接受 4 个参数:

    // 前一个值、当前值、项的索引值、原数组对象

    console.log(prev, '---', cur, '---', index, '---', array)

    return prev + cur

    }, 3)

    console.log(sum) // 18 = 15 + 3

    1

    2

    3

    4

    5

    6

    7

    8

    9

    与之相对应的还有一个 Array.reduceRight() 方法,区别是这个是从右向左操作的



    十七、Array.from() 将类数组转化为数组

    let arrayLike = {

    '0': 'a',

    '1': 'b',

    '2': 'c',

    '3': 'd',

    length: 4

    }

    // ES5 写法

    let arr1 = [].slice.call(arrayLike) // ['a', 'b', 'c', 'd']



    // ES6

    let arr2 = Array.from(arrayLike) // ['a', 'b', 'c', 'd']

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    十八、Array.of() 方法用于将一组值转化为数组

    Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。



    Array.of(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]

    Array.of('abcd') // ['abcd']

    Array.of('abcd').length // 1

    Array.of() // []



    // Array.of 方法的实现

    function ArrayOf () {

    return [].slice.call(arguments)

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    十九、数组实例的 find() 和 findIndex()

    数组实例的 find() 方法,用于找出第一个符合条件的数组成员

    它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为 true 的成员,然后就返回该成员,如果没有符合条件的成员,则返回 undefined

    let arr = [1, 2, 3, 4, 5]

    let value= arr.find((item, index, array) => {

    // item 表示循环遍历数组的每一项

    // index 每一项对应的索引值

    // array 原数组对象

    return item > 3

    })

    console.log(value) // 4

    console.log(arr) // [1, 2, 3, 4, 5]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    数组实例的 findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回 -1

    let arr = [1, 2, 3, 4, 5]

    let index = arr.findIndex((item, index, array) => {

    return item > 3

    })



    console.log(index) // 3



    [NaN].indexOf(NaN) // -1

    [NaN].findIndex(value => Object.is(NaN, value)) // 0

    [NaN].includes(NaN) // true

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    由此可见:一般用来判断数组中是否存在某个值,推荐使用 includes



    二十、扁平化数组 flat() 方法 -----> 不会改变原数组

    let arr = [1, [2, 3, [4, 5, [6]]]]

    let arrFlat = arr.flat(Infinity)

    console.log(arrFlat) // [1, 2, 3, 4, 5, 6]

    console.log(arr) // [1, [2, 3, [4, 5, [6]]]]

    1

    2

    3

    4

    利用递归实现数组扁平化



    let arrayFlat = []

    let myFlat = (arr) => {

    for (let i = 0; i < arr.length; i++) {

    let item= arr[i]

    // 判断 arr[i] 是否是数组

    if (Array.isArray(item)) {

    // 如果是数组,继续调用函数 myFlat

    myFlat(item)

    } else {

    arrayFlat.push(item)

    }

    }

    return arrayFlat

    }



    蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

彻底解决小程序无法触发SESSION问题

seo达人

一、首先找到第一次发起网络请求的地址,将服务器返回set-cookie当全局变量存储起来

wx.request({
  ......
  success: function(res) {
    console.log(res.header);
    //set-cookie:PHPSESSID=ic4vj84aaavqgb800k82etisu0; path=/; domain=.fengkui.net

    // 登录成功,获取第一次的sessionid,存储起来
    // 注意:Set-Cookie(开发者工具中调试全部小写)(远程调试和线上首字母大写)
    wx.setStorageSync("sessionid", res.header["Set-Cookie"]);
  }
}) 

二、请求时带上将sessionid放入request的header头中传到服务器,服务器端可直接在cookie中获取

wx.request({
  ......
  header: {
    'content-type': 'application/json', // 默认值
    'cookie': wx.getStorageSync("sessionid")
    //读取sessionid,当作cookie传入后台将PHPSESSID做session_id使用
  },
  success: function(res) {
    console.log(res)
  }
}) 

三、后台获取cookie中的PHPSESSID,将PHPSESSID当作session_id使用

<?php
// 判断$_COOKIE['PHPSESSID']是否存在,存在则作session_id使用
if ($_COOKIE['PHPSESSID']) {
    session_id($_COOKIE['PHPSESSID']);
}

session_start();
echo session_id(); 

jqGrid 表格底部汇总、合计行footerrow处理

seo达人

jqGrid提供了表格底部汇总、合计行功能,我们先看下user-guide关于jqGrid合计行都有哪些说明?然后再看个DEMO,看看jqGrid表格底部汇总、合计行到底如何实现。



1、user-guide关于jqGrid合计行的说明

1)表格配置:footerrow, boolean, 默认false

If set to true this will place a footer table with one row below the gird records and above the pager. The number of columns equal those specified in colModel

表格是否显示底部合计行。



2)表格配置:userDataOnFooter,boolean,默认false

When set to true we directly place the user data array userData in the footer if the footerrow parameter is set to true. The rules are as follows: If the userData array contains a name which matches any name defined in colModel, then the value is placed in that column. If there are no such values nothing is placed. Note that if this option is used we use the current formatter options (if available) for that column. See footerData method.

如果设为true,则userData可以用来填充汇总行。



3)汇总行赋值:footerData([string action], [object data], [boolean format])

This method gets or sets data on the grid footer row. When set data in the footer row, the data is formatted according to the formatter (if defined) in coModel. The method can be used if footerrow option is set to true.

parameters

string action - can be ‘get’ or ‘set’. The default is get. ‘get’ returns an object of type name:value, where the name is a name from colModel. This will return data from the footer. The other two options have no effect in this case. ‘set’ takes a data object and places the values in the footer The value is formatted according to the definition of the formatter in colModel - see next parameter. The object should be in name:value pair, where the name is the name from colModel

object data - data to be set in the footer in name:value pair, where the name should correspond to the name of colModel in order to be set in the appropriate cell.

boolean format - default is true. This instruct the method to use the formatter (if set in colModel) when new values are set. A value of false will disable the using of formatter



2、一个DEMO,如何利用gridComplete事件进行表格数据汇总并赋值给合计行

1)案例截图



2)html代码



<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8" />

<title>jggrid底部汇总行</title>



<link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />

<link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.5.0/css/font-awesome.min.css" />

<link rel="stylesheet" href="https://cdn.bootcss.com/jqueryui/1.11.0/jquery-ui.min.css" />

<link rel="stylesheet" href="https://js.cybozu.cn/jqgrid/v5.3.1/css/ui.jqgrid.css" />

<script src="https://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"&gt;&lt;/script&gt;

<script src="https://js.cybozu.cn/jqgrid/v5.3.1/js/jquery.jqGrid.min.js"&gt;&lt;/script&gt;

<script src="https://js.cybozu.cn/jqgrid/v5.3.1/js/i18n/grid.locale-en.js"&gt;&lt;/script&gt;

</head>

<body>

<div class="page-content container">

<div class="page-body"> <!-- page-body -->

<div class="panel panel-default" id="panel-orders">

<table id="orders"></table>

</div>

</div>

</div>

<script type="text/javascript">

var data = [];

function getBills() {

var rowCount = 10;

for (var i = 0; i < rowCount; i ++) {

data.push({

sid: i,

goods_no: i + 1,

goods_name: '零件名称' + rowCount + i,

car_type_name: '车型' + rowCount + i,

package_name: '包装器具' + rowCount + i,

unit_name: '件',

snp: 0.89,

bill_amount: rowCount + i,

goods_count: rowCount + i,

bill_no: 'BN0000000' + i,

qrcode: '1000000000' + i,

barcode: '1000000000' + i,

})

}

$("#orders").jqGrid("clearGridData").jqGrid('setGridParam',{data: data || []}).trigger('reloadGrid');

}

$(function() {

$("#orders").jqGrid({

colModel: [

{label: "零件号", name: "goods_no", width: 60},

{label: "零件名称", name: "goods_name", search:false, width: 180},

{label: "车型", name: "car_type_name", width: 70},

{label: "包装器具", name: "package_name", width: 70},

{label: "单位", name: "unit_name", width: 40},

{label: "订单号", name: "bill_no", width: 120},

{label: "订单数量", name: "goods_count", width: 80},

],

datatype: 'local',

rownumbers: true,

height: 300,

rowNum: 1000,

footerrow: true,

gridComplete: function() {

var rows = $("#orders").jqGrid("getRowData"), total_count = 0;

        for(var i = 0, l = rows.length; i<l; i++) {

        total_count += (rows[i].goods_count - 0);

        }

        $("#orders").jqGrid("footerData", "set", {goods_name:"--合计--",goods_count:total_count});

        }

});

getBills();

});

</script>

</body>

</html>



3)代码说明:



表格构建时,设置:footerrow: true

gridComplete(jqGridGridComplete)事件处理,进行数据汇总并赋值给合计行

gridComplete fires after all the data is loaded into the grid and all other processes are complete. Also the event fires independent from the datatype parameter and after sorting paging and etc. Does not fire if datatype is a defined as function.



4)获取汇总行数据

var row = $("#orders").jqGrid(“footerData”, “get”);

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

vue-router的router-link详解

seo达人

<router-link>

<router-link> 组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 <a> 标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。



<router-link> 比起写死的 <a href="..."> 会好一些,理由如下:



无论是 HTML5 history 模式还是 hash 模式,它的表现行为一致,所以,当你要切换路由模式,或者在 IE9 降级使用 hash 模式,无须作任何变动。

在 HTML5 history 模式下,router-link 会守卫点击事件,让浏览器不再重新加载页面。

当你在 HTML5 history 模式下使用 base 选项之后,所有的 to 属性都不需要写 (基路径) 了。

示例代码:



字符串形式,会默认在当前路由下给字符串前面加



<router-link to='propsView'>字符串形式One</router-link><br>

<router-link :to="{path: 'propsView', query: {id: 1}}" replace>字符串形式Two</router-link><br>

路径形式 



<router-link to='/test/propsView'>路径形式One</router-link><br>

<router-link :to="{path: '/test/propsView'}">路径形式Two</router-link><br>

命名的路由 



<router-link :to="{name: 'test', params: {userId: 123}}">跳转至test路由</router-link><br>

想要 <router-link> 渲染成某种标签,例如 <li>。 于是我们使用 tag prop 类指定何种标签, 同样它还是会监听点击,触发导航。默认值: "a"



<router-link :to="{name: 'test'}" tag="li">渲染成li标签</router-link><br>

设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。 



<router-link :to="{name: 'test'}" replace>replace导航后不会留下 history 记录</router-link>


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

bootstrap+spring boot实现面包屑导航

seo达人

面包屑导航介绍

一般的内容型网站,例如CMS都会有这种面包屑导航。总结起来它有以下优势:







让用户了解目前所在的位置,以及当前页面在整个网站中所在的位置;

体现了网站的架构层级;提高了用户体验;

减少返回到上一级页面的操作;

 



实现效果

那我们应该如何实现?我看网上多数都是只提供静态实现,



这里我结合bootstrap 和 spring boot以及mysql来做一个完整的例子。







表结构设计

图里面的菜单其实是分级维护上下级关系的。我这里用到了2级,表里有level字段标记。



点击第1级加载第2级分类,点击第2级分类名称则展示面包屑导航。



CREATE TABLE tb_category (

  id bigint(20) NOT NULL AUTO_INCREMENT,

  category_name varchar(100) NOT NULL,

  parent_id bigint(20) DEFAULT NULL,

  level tinyint(1) DEFAULT NULL,

  PRIMARY KEY (id)

) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

insert into tb_category values(1,'Java文档',0,1);

insert into tb_category values(2,'Java多线程',1,2);

insert into tb_category values(3,'Spring Boot',1,2);

insert into tb_category values(4,'微服务实战',1,2);

 

insert into tb_category values(5,'Java视频',0,1);

insert into tb_category values(6,'Java基础',5,2);

insert into tb_category values(7,'Java基础',1,2);

commit;

 



前端代码

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"

      xmlns:sec="http://www.thymeleaf.org/extras/spring-security"&gt;

 

<head>

    <meta charset="utf-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>响应式布局</title>

    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

</head>

 

<body>

<input type="text" id="ctx" hidden="hidden" th:value="${#request.getContextPath()}">

<div class="container-fluid">

    <!--页头-->

    <nav class="navbar navbar-inverse">

        <div class="container-fluid">

            <!-- Brand and toggle get grouped for better mobile display -->

            <div class="navbar-header">

                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"

                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">

                    <span class="sr-only">Toggle navigation</span>

                    <span class="icon-bar"></span>

                    <span class="icon-bar"></span>

                    <span class="icon-bar"></span>

                </button>

                <a class="navbar-brand" th:href="@{'/breadCrumb'}">Java分享</a>

            </div>

 

            <!-- Collect the nav links, forms, and other content for toggling -->

            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">

                <ul class="nav navbar-nav" id="navbar">

                </ul>

            </div>

        </div>

    </nav>

    <!--面包屑-->

    <ol class="breadcrumb">

    </ol>

    <div class="list-group" id="submenu-list">

    </div>

</div>

<script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"&gt;&lt;/script&gt;

<script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/js/bootstrap.min.js"&gt;&lt;/script&gt;

<script>

    var ctx=$("#ctx").val();

    $(function () {

       // 获取一级菜单

        getMenu(null,1);

    });

 

    function getMenu(id, level){

        var json = {parentId:id,level:level};

        $.ajax({

            url: ctx+"/myCategory/list",

            type: "POST",

            contentType: "application/json",

            dataType: "json",

            data: JSON.stringify(json),

            success: function (result) {

                var text='';

                if (result.success) {

                    if(result.data != null){

                        // 一级菜单

                        if(level!=null){

 

                            $.each(result.data, function (i, r) {

                                text += '<li><a href="#" οnclick="getMenu('+r.id+')">'+r.categoryName+'</a></li>'

                            });

                            $("#navbar").empty();

                            $("#navbar").append(text);

                        }

                        // 子菜单

                        if(id!=null){

                            $.each(result.data, function (i, r) {

                                console.log(i);

                                text += '<a href="#" class="list-group-item" οnclick="getBreadCrumb('+r.id+')">'+r.categoryName+'</a>'

                            });

                            $("#submenu-list").empty();

                            $("#submenu-list").append(text);

                        }

                    }

                } else {

                    alert(result.message);

                }

            }

        });

    }

 

    // 生成面包屑导航

    function getBreadCrumb(id) {

        var param = {id:id};

        $.ajax({

            url: ctx+"/myCategory/getParentList",

            type: "GET",

            data: {"id":id},

            success: function (result) {

                var text='';

                if(result.data!=null){

                    text = '<li><a href="#">首页</a></li>';

                    $.each(result.data, function (i, r) {

                        text += '<li><a href="#">'+r.categoryName+'</a></li>'

                    });

 

                    $(".breadcrumb").empty();

                    $(".breadcrumb").append(text);

                }

            }

        })

    }

</script>

</body>

 

</html>

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

【一分钟阅读】关于组件化,我有一些小建议

seo达人

随着公司项目多端化,开发所需要注意的细节越来越多。我在会议上提出组件化开发,希望能把业务细节与技术细节区分开来。



 一、组件化流程

首先我们需要找到切入点,我采取的是通过模仿element-ui的组件,先让我们美工小姐姐,照着element的组件库描绘一版我们自己的组件,内容包括 颜色、字体、按钮、图片 等基础UI组件。这就是我们组件化第一步,UI 组件形成。



其次是业务组件的补充,这方面我和项目经理还有其他前端一起商讨,将跨场景跨页面同样效果的部分给抽象成组件。组件化第二步,业务组件形成。



然后就是漫长的更迭与组件补充。



二、组件化细节处理

2.1 全局文件布置

无论是UI组件还是业务组件,都包含着class与css。



变量值我选择存放在两个公共文件内:



一个负责管理class名,诸如 x-btn-s,x-btn-m,x-btn-l,x-pic-s,声明规则:公司名-组件名-尺寸(业务场景)。



另一个负责管理 css 变量值, 诸如 $-font-s: 12px,$-font-m:16px; $-font-l:24px;$-background-warn: #f00;声明规则:$-相关样式-大小(颜色)。



再通过 exports 与 import 对全局文件进行调用。



2.2 组件的多样化使用

通过全局文件的配置,我们对组件的调用从一对一调用变成了一对多调用。如下:



使用全局变量前,我们只能通过以下形式调用



<x-button/>

现在我们可以通过:class的形式调用<x-button/>的多种形态,如下:



<x-button type="$-x-btn-warn' size-'$-x-btn-s'>注册</x-button>

当然,我们还需要在组件内部定义好:class部分,配置如下:



<template>

  <button

    class="x-button"

    :class="[

      type ? 'x-button--' + type : '',

      buttonSize ? 'x-button--' + buttonSize : '',

    ]"

  >

  </button>

</template>

<script>

  export default {

    name: 'XButton',

    props: {

      type: {

        type: String,

        default: 'default'

      },

      size: String,

    },

  };

</script>

2.3 slot 插槽的配置与使用

合理使用 slot 插槽,例如:组件内嵌组件,组件内嵌文字,内嵌 iconfont 等;



三、 组件的配置

在 app.js 中使用 vue.use(components) 对组件进行配置,再在相关页面进行引用。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

jQuery与Ajax:“特别的”load()方法(筛选文档、传递方法、回调函数)

seo达人

“大名鼎鼎的”jQuery因为其极简的引用方式而在N年前备受追捧,而今“浪潮”过去,还剩下什么?

我认识jQuery,只是在去年接触ajax时了解,从而感兴趣,进而深入探究(其实也没多深入,只是相关的看了一下)。不得不说,jQuery对ajax支持的四个type:post(一般用于发送)、get(一般常用于接收)、put(修改)、delete(删除) 令我非常震撼,太**实用了。

这其中,post和get是最常用的(因为好像说不是所有的浏览器都支持put和delete),具体的我在 这篇文章 中以JS方式提到,这里不再赘述。



load()

load()方法时jQuery中操作上最为简单的Ajax方法,能载入其他的HTML代码并插入到DOM中。其基本格式为:



load(url [,data] [,callback])

1

参数意义:



url: String类型,请求HTML页面的URL地址

data(可选): Object类型,发送至服务器的key/value数据

callback(可选): Function,请求完成时的回调函数,无论请求成功或失败

为什么说它是“特别的”呢?因为它只用于文档流(html)的操作,而且,既可以是get操作,又可以是post操作:



基本示例:



//如果是jsp代码,这里要加一行:

// <%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>

<head>

    <title>请求的文件</title>

</head>

<body>

    <div class="comment">

        <h6>张三:</h6>

        <p class="para">沙发</p>

    </div>

    <div class="comment">

        <h6>李四:</h6>

        <p class="para">板凳</p>

    </div>

    <div class="comment">

        <h6>王五:</h6>

        <p class="para">地板</p>

    </div>

</body>

</html>



//如果是jsp代码,这里要加一行:

//<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>

<head>

    <title>发送ajax的文件</title>

    <script src="js/jquery-2.1.0.js" type="text/javascript"></script>

    //如果是jsp代码,上面这一行要换成:<script src="<%=request.getContextPath()%>/js/jquery-2.1.0.js" type="text/javascript"></script>

    <script type="text/javascript">

        $(function () {

            $("#send").on("click", function () {

                $("#resText").load("test.jsp");

            });

        });

    </script>

</head>

<body>

    <input type="button" id="send" value="Ajax获取">

    <div class="comment">已有评论:</div>

    <div id="resText"></div>

</body>

</html>



上面是“载入文档”,它还可以“筛选载入的文档”:

如果只需要加载某页面内的某些元素,那么可以使用load()方法的URL参数来达到目的。通过为 URL参数 指定选择符,就可以很方便地从加载过来的HTML文档里筛选出所需要的内容。



load()方法的URL参数的语法结构为:“url selector”。注意,URL和选择器之间有一个空格:



$(function () {

    $("#send").on("click", function () {

        $("#resText").load("test.html .para");

    });

});



传递方式:

load()方法的传递方式根据 参数data 来自动指定。如果没有参数传递,则采用GET方式传递;反之,则会自动转换为POST方式:



//无参数传递,GET方式

 $("#resText").load("test.html .para", function(){

//....

});

//有参数传递,POST方式

 $("#resText").load("test.html .para",{name:"tom", age:"18}, function(){

//....

});



回调函数:

对于必须在加载完成后才能继续的操作,load()方法提供了 回调函数 ,该函数 有3个参数 ,分别代表请求返回的内容、请求状态和XMLHttpRequest对象 ,jQuery代码如下:



 $("#resText").load("test.html", function(responseText, textStatus, XMLHttpRequest){

//responseText:请求返回的内容——等同于js-ajax时的“得到服务器响应的文本格式的内容”(注意:js操作中的get、post...都在open()中规定)

//textStatus:请求状态:success、error、notmodified、timeout4种

//XMLHttpRequest:XMLHttpRequest对象——这玩意一般用在判断浏览器适用类型上

});

//注意:在load()方法中,无论Ajax请求是否成功,只要请求完成(complete)后,回调函数就被触发。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

JS基础知识整理06-函数

seo达人

使用function关键字定义函数

函数声明会被提升(Hoisting),将声明移动到当前作用域顶端的默认行为。



参数:

如果函数调用的参数太多(超过声明),则可以使用函数的内置对象arguments

arguments.length 会返回函数被调用时收到的参数数目

arguments[index]可以得到相应的参数



传递对象的时候是使用引用来传递的,如果函数修改了对象属性,则原始对象也改变了。





调用:

以函数形式调用函数:(这种方式调用默认的是全局对象调用)

function myFunction(a, b) {

return a * b;

}

myFunction(10, 2);



作为方法来调用函数:(这种方式调用属于函数的拥有者myObject)

var myObject = {

firstName:"Bill",

lastName: "Gates",

fullName: function () {

return this.firstName + " " + this.lastName;

}

}

myObject.fullName(); 



通过函数构造器来调用函数:(如果函数调用的前面是 new 关键字,那么这是一个构造函数调用)

function myFunction(arg1, arg2) {

this.firstName = arg1;

this.lastName  = arg2;

}

var x = new myFunction("Bill", "Gates");

x.firstName; 



call()和apply()方法:

var person = {

fullName: function() {

return this.firstName + " " + this.lastName;

}

}

var person1 = {

firstName:"Bill",

lastName: "Gates",

}

var person2 = {

fullName: function(city, country) {

return this.firstName + " " + this.lastName + "," + city + "," + country;

}

}



call() 方法是预定义的 JavaScript 方法。

它可以用来调用所有者对象作为参数的方法。

通过 call(),您能够使用属于另一个对象的方法。

如:

person.fullName.call(person1)// person1来调用person的fullName方法



call()可以带参数,参数对应按顺序的传给方法

person2.fullName.call(person1,"Seattle", "USA")



apply()方法和call()方法类似

区别在于接收参数的方式不一样。

call(obj,"x","y") 方法分别接受参数

apply(obj,["x","y"]) 方法接收数组形式的参数





箭头函数:(ES6)

箭头函数不需要function关键字、return关键字和大括号

var x = function(x, y) {

  return x y;

}



var x = (x, y) => x
y;

两个的作用相同。



箭头函数没有自己的this、如果函数是单个语句,则只能省略 return 关键字和大括号

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

Hibernate--使用离线查询DetachedCriteria完成对列表的筛选

seo达人

User表:





User类:

package pers.zhang.domain;



public class User {



private Long user_id;

private String user_code;

private String user_name;

private String user_password;

private String user_state;

public Long getUser_id() {

return user_id;

}

public void setUser_id(Long user_id) {

this.user_id = user_id;

}

public String getUser_code() {

return user_code;

}

public void setUser_code(String user_code) {

this.user_code = user_code;

}

public String getUser_name() {

return user_name;

}

public void setUser_name(String user_name) {

this.user_name = user_name;

}

public String getUser_password() {

return user_password;

}

public void setUser_password(String user_password) {

this.user_password = user_password;

}

public String getUser_state() {

return user_state;

}

public void setUser_state(String user_state) {

this.user_state = user_state;

}

}



ORM元数据:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC 

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"&gt;

<hibernate-mapping package="pers.zhang.domain" >

<class name="User" table="sys_user" >

<id name="user_id"  >

<generator class="identity"></generator>

</id>

<property name="user_code" column="user_code" ></property>

<property name="user_name" column="user_name" ></property>

<property name="user_password" column="user_password" ></property>

<property name="user_state" column="user_state" ></property>

</class>

</hibernate-mapping>



控制层:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

request.setCharacterEncoding("utf-8");

//获得查询参数

String userIdStr = request.getParameter("userId");

String userName = request.getParameter("userName");

//获得离线查询对象

DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class);

//拼装查询条件

if(userIdStr != null && !"".equals(userIdStr)) {

Long userId = (long) Integer.parseInt(userIdStr);

detachedCriteria.add(Restrictions.eq("user_id", userId));

}

if(userName != null && !"".equals(userName)) {

detachedCriteria.add(Restrictions.like("user_name", userName, MatchMode.ANYWHERE));

}



//作为参数传递给service层

UserService userService = new UserService();

List<User> list = userService.findUserByCondition(detachedCriteria);



request.setAttribute("userList", list);

request.getRequestDispatcher("list2.jsp").forward(request, response);

}



Service层:

public List<User> findUserByCondition(DetachedCriteria detachedCriteria) {

//传递给Dao层

UserDao userDao = new UserDao();

return userDao.findUserByCondition(detachedCriteria);

}

1

2

3

4

5

Dao层:

public List<User> findUserByCondition(DetachedCriteria detachedCriteria) {

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();



//关联session

Criteria criteria = detachedCriteria.getExecutableCriteria(session);

//查询

List<User> list = criteria.list();

return list;



}



前端页面:

忘记写查询数据回显了…



<%@ page language="java" contentType="text/html; charset=utf-8"

    pageEncoding="utf-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title></title>

<script type="text/javascript" src="js/jquery-2.1.0.js" ></script>

<script type="text/javascript" src="js/bootstrap.min.js" ></script>

<link rel="stylesheet" href="css/bootstrap.css" />

</head>

<body>

<form class="form-inline" role="form" method="post" action="${pageContext.request.contextPath }/findUserByCondition">

  <div class="form-group">

    <input type="text" class="form-control" id="exampleInputEmail2" placeholder="用户ID" name="userId">

  </div>

  <div class="form-group">

    <input type="text" class="form-control" id="exampleInputPassword2" placeholder="用户名" name="userName">

  </div>

  <button type="submit" class="btn btn-default">筛选</button>

</form>



<div style="text-align: center; width: 600px;">

<table class="table table-hover">

  <tr><td>编号</td><td>用戶ID</td><td>用户名</td><td>昵称</td><td>密码</td></tr>

  <!-- 显示数据 -->

  <c:forEach items="${userList }" var="list">

  <tr><td>${list.user_id }</td><td>${list.user_code }</td><td>${list.user_name }</td><td>${list.user_password }</td><td>${list.user_state }</td></tr>

  </c:forEach>

</table>

</div>





</body>

</html>



测试:



蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

CSS3 终极布局指南

seo达人

对于同一个页面布局,几乎每个人的写法都不一样,有人喜欢Flex弹性盒子布局,有的人则喜欢Float浮动布局,有些人喜欢Margin负值布局,等等。从来就没有一种统一的布局方案,现在大伙写代码也就放飞自我,只要能在规定的环境上跑起来,不会乱就行了。但是,身为脑瘫正经前端,我们还是有必要分出在不同情况应使用的布局。



这一篇博客比起作为文章,不如作为工具书。当你对布局迷茫时,不妨打开看看。我们可以不求甚解,只需要先把所有布局掌握熟练。



文章目录

CSS3 终极布局指南

正常布局(语义化布局)

正常布局,按照浏览器的内置CSS渲染

应用场景

带来的问题



不兼容

没有自适应

解决方案

Float浮动布局

什么是浮动?

浮动元素的排列

浮动解决的布局问题

浮动带来的问题

父元素高度坍缩

不希望浮动时清除浮动

总结

定位布局

定位的应用

static

relative

absolute

高度坍缩

对比float

总结

fixed

祖先未使用transform:none

使用

sticky 粘性定位

Flex布局

浏览器支持

Flex使用介绍

Flex容器属性

flex-direction 排布方向

flex-wrap 控制换行

flex-flow [排布方向/控制换行]的简称

justify-content 子项目在主轴上的排布

align-items 子项目在交叉轴排布

align-content 定义多根轴线排布

Flex子项属性

order 子项排布靠前排名

flex-grow 子项放大比例

flex-shrink 子项缩小比例

flex-basis

flex

align-self

Grid 布局

参考

声明

正常布局(语义化布局)

正常布局,按照浏览器的内置CSS渲染

大道至简在远古时代,CSS还有没被发明,浏览器渲染HTML的时候,只是按照规定好的如标题、段落、表格等格式渲染。且不同的浏览器对于相同元素的渲染也是不同的,现在这项传统艺能保留到了今天。



不过到了今天,正常布局也稍微被W3C重视了一下。在HTML5的规定中,新增加了不少语义化的元素。所谓语义化元素就是让大家规定它就是来做这件事的。



新增加的语义化元素。



标签名称 作用

hearder header 标签定义文档的页面组合,通常是一些引导和导航信息。

nav nav 标签定义显示导航链接不是所有的成组的超级链接都需要放在nav标签里。nav标签里应该放入一些当前页面的主要导航链接。 例如在页脚显示一个站点的导航链接(如首页,服务信息页面,版权信息页面等等),就可以使用nav标签,当然,这不是必须的。

article article标签装载显示一个独立的文章内容。例如一篇完整的论坛帖子,一则网站新闻,一篇博客文章等等,一个用户评论等等 artilce可以嵌套,则内层的artilce对外层的article标签有隶属的关系。例如,一个博客文章,可以用article显示,然后一 些评论可以以article的形式嵌入其中。

section section 标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。

aside aside 用来装载非正文类的内容。例如广告,成组的链接,侧边栏等等。

hgroup hgroup 标签用于对网页或区段的标题元素(h1-h6)进行组合。例如,在一个区段中你有连续的h系列的标签元素,则可以用hgroup将他们括起来。

time time 标签定义公历的时间(24 小时制)或日期,时间和时区偏移是可选的。该元素能够以机器可读的方式对日期和时间进行编码,这样, 举例说,用户代理能够把生日提醒或排定的事件添加到用户日程表中,搜索引擎也能够生成更智能的搜索结果。

mark mark 标签定义带有记号的文本。请在需要突出显示文本时使用 <mark> 标签。

figure figure标签规定独立的流内容(图像、图表、照片、代码等等)。figure 元素的内容应该与主内容相关,但如果被删除,则不应对文档流产生影响。

可以看到HTML5规定中增加了不少新的标签,但是这些标签大部分并不是为了补充正常的文档布局的,而是服务于搜索引擎的爬虫。不要觉得页面布局只是给人看的!对于布局清晰地页面,搜索引擎的爬虫也会给出更高的分数。



应用场景

作为布局的基石。

开发较为单一的页面,比如电子书阅读页面,面向视力障碍人士的报纸页面等。

带来的问题



使用浏览器默认的CSS意味着你不可定制自己的页面,对于像<ul>、<table>这样的标签,你也只能忍受上世纪的设计风格了。



不兼容

先前说了,每个浏览器对于基础的HTML节点的渲染都不一样,也就是说你写的页面在IE上是一个风格,换到Safari上又是一种风格。



没有自适应

有一说一,正常布局(语义化)还是用来当基石比较好,对于响应式、自适应那还得看下面伙计的发挥。



解决方案

解决挫的方法就是使用style属性,也就是使用CSS美化我们的页面。解决不兼容的问题则需要初始化CSS,大伙应该在不少的页面的头部见过一大坨css代码吧,就像下面Google页面。(部分)



body{color:#000;margin:0}body{background:#fff}a.gb1,a.gb2,a.gb3,.link{color:#1a0dab !important}.ts{border-collapse:collapse}.ts td{padding:0}#res,#res .j{line-height:1.2}.g{line-height:1.2;text-align:left;}.ti,.bl{display:inline}.ti{display:inline-table}#rhs_block{padding-bottom:15px}a:link,.w,#prs a:visited,#prs a:active,.q:active,.q:visited,.kl:active,.tbotu{color:#1a0dab}.mblink:visited,a:visited{color:#609}.cur,.b{font-weight:bold}.j{width:42em;font-size:82%}.s{max-width:48em}.sl{font-size:82%}

1

页面初始化也是很重要的,它可以使我们的代码健壮的运行在各个环境的浏览器上。



Float浮动布局

什么是浮动?

如果首先要认识一个物品,认识一个东西的最好方式是了解为什么会产生它,也就是要翻它的历史。——NaoTan·Ma·Nong





看上图,啊,报社最爱的环绕,一堆文字环绕一张图片,这样的布局使得页面紧凑,并且有较好的阅读体验。如果我们要在HTML中实现这样的布局应当怎么设置呢?手动设置换行?不行,缺少灵魂。如果能使文字绕过图片排列下来就好了。



于是Float属性出世,它不仅解决了文字环绕问题,并且带来了新的布局方案。





如上面的布局,我们用代码实现主要部分。

.side-bar{

    float:left;

}

.main-content{

    float:left;

}

1

2

3

4

5

6

浮动元素的排列

当一个元素被设置为浮动元素时,首先,它会被移除文档流,设置float:left|right则元素会向设置方向排列,直到遇到父元素边框(或者说最大宽度)或者另一个浮动元素时停止。



当设置父元素display:flex时,子元素的浮动值无效!



浮动解决的布局问题

使用浮动我们可以解决传统的两列布局、三列布局的自适应。下面代码是用浮动实现的两列布局。



<!DOCTYPE html>

<html lang="zh">



<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>

    <style>

        body,

        html {

            margin: 0;

            background-color: rgb(228, 228, 228);

        }



        header {

            margin-bottom: 20px;

        }



        footer {

            margin-top: 20px;

        }



        .layout {

            height: 50px;

            border: 1px solid black;

        }



        aside {

            width: 25%;

            float: left;

            border: solid 1px black;

            height: 500px;

        }



        article {

            width: 70%;

            border: solid 1px black;

            height: 500px;

            float: right;

        }

    </style>

</head>



<body>

    <header class="layout"></header>

    <div style="overflow:auto;">

        <aside>



        </aside>

        <article>



        </article>

    </div>



    <footer class="layout"></footer>

</body>



</html>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

效果如下





浮动带来的问题

父元素高度坍缩

一般来说新手在学习浮动布局之后,遇到的第一个问题就是父元素高度坍缩。什么是高度坍缩?







看上图,在父元素的四个子元素均为浮动元素,由于浮动元素的特性浮动元素脱离文档流,所以父元素不会被撑起高度。



如何解决?答案很简单,使用BFC块级格式上下文。当父元素为BFC的时候,内部计算高度会带上浮动元素的高度。



不希望浮动时清除浮动

使用clear属性可以使元素清除周围的浮动。





如上图,对段落文字清除浮动,导致原本环绕的文字,另起一行。顺便解决了高度坍缩的问题。



总结

浮动在带来方便的同时也引入了新的问题,如果能处理好这些问题那么浮动也可以当做布局的主力,但是都已经9102年了,我们应该追随CSS3的布局方案,尽量少使用浮动。



定位布局

收拾房子的时候总会把物品按照相应的位置放置,这样会让房间看上去更加整洁。所以,我们CSS也是可以这样做的。



使用position属性,调整元素的位置。position一共有四种定位类型:定位元素、相对定位、绝对定位、粘性定位,五种取值:static、relative、absolute、fixed、sticky。



名称 描述 定位类型

static 该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index属性无效。 定位元素

relative 该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。 相对定位

absolute 不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。 绝对定位

fixed 不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。 绝对定位

sticky 盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky对 table 元素的效果与 position: relative相同。 粘性定位

一般使用position属性时,会使用其相对定位与绝对定位、粘性定位,它们都使用top、bottom、left、right来调整自身位置,但是调整的基准不一样。



定位的应用

static

static是元素正常出现在文档流中的定位,文档流中的排列为自上而下,自左至右。一般来说block元素自占一行,inline元素横向排列。



正常情况下在我们的页面中大部分元素为static定位,对于一些特殊需求我们需要使用其他定位。比如像wiki中的关键词,鼠标移动上去的时候,关键词下面显示式卡片。



relative

relative是在实现一些特殊布局的时候经常使用的一种定位方式。设置为relative的元素并不会脱离文档流,但是可以通过top、bottom、left、right调整元素对于默认基准的位置。



.box {

  display: inline-block;

  width: 100px;

  height: 100px;

  background: red;

  color: white;

}


two {

  position: relative;

  top: 20px;

  left: 20px;

  background: blue;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14



使用相对定位可以实现一些炫酷的效果。



.content{

        text-align: center;

        margin: 20px;

    }

    .card{

        position: relative;

        display: inline-block;

        width: 200px;

        height: 200px;

        background-color: darkgray;

        top: 210px;

        right: 170px;

        visibility: hidden;

    }

    span:hover+.card{

        visibility:visible;

    }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

    <div class="content">

        <span>鼠标移到我身上!</span>

        <div class="card">



        </div>

    </div>

1

2

3

4

5

6

效果





但是,使用相对定位依然会出现一些问题。relative定位并不会脱离文档流,所以.content元素的高度为200px。



absolute

与relative定位不同的是absolute是脱离文档流的,而且相对基准是position属性不为static的祖先元素,如果祖先都是static则元素相对body定位。并且,对于absolute元素,如果不设置top/bottom/left/right的话依然排列在正常布局位置。



html,

        body {

            margin: 0;

        }



        .content {

            position: relative;

            / top: 50px; /

            margin-top: 50px;

        }



        .static {

            position: static;

        }



        .relative {

            position: relative;

            margin: 20px 0;

        }



        .absolute {

            display: inline-block;

            width: 50px;

            height: 50px;

            background-color: lightcoral;

            position: absolute;

        }



        .non-ab {

            display: inline-block;

            width: 50px;

            height: 50px;

            background-color: darkblue;

            margin-left: 100px;

        }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

<div class="content">

        <div style="height: 50px;"></div>

        <div class="static">

            <div class="non-ab">



            </div>

            <div class="absolute">



            </div>



        </div>

        <div class="relative">

            <div class="absolute">



            </div>

            <div class="non-ab">



            </div>

        </div>

    </div>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20





上面的代码很有意思,有兴趣的同学可以放在codepen上面跑一下子。这个例子验证了absolute的排列方式。当我们知道我们在做什的时候,也就不需要墨守成规(对于absolute元素的父元素统一设置relative属性)了。



高度坍缩

只要是脱离了文档流的元素都会出现高度坍缩,所以在使用absolute属性时,请确保父元素不会因此而改变。



对比float

Float与absolute都会使元素脱离文档流,但是众所周知对相同元素设置float与设置absolute会出现不同的效果。这是因为float与absolute本身的排列不一样。



float:脱离文档流,排列时以父元素为基准,并且会为占用其他浮动元素的位置。



absolute:脱离文档流,排列时分情况:第一种情况,对于未设置left、right、top、bottom属性的元素,排列在正常显示位置,并不占用空间。第二种情况,设置位置属性的元素,基于非static祖先元素排列。



上面两者比较显著的差异为float会影响下一个float元素,但是absolute元素不会。



总结

说absolute为绝对定位也并不贴切,它也是基于祖先元素定位的,只是脱离了文档流。我个人还是比较推荐在处理元素相对位置问题上使用absolute属性的,但前提是您已经深刻理解了absolute的排列方式。



fixed

不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。



fixed元素也会脱离文档流,并且和absolute元素一样,当不设置任何left、top、bottom、right值的时候,元素依然按照正常定位的位置放置。



祖先未使用transform:none

当祖先元素未使用transform:none的时候,fixed元素相对于该祖先元素进行定位。







在上面的图片中,我设置小黄块为fiexd属性,并让父元素设置为 使用transform:matrix(1, 0, 0, 1, 0, 0);,这时候小黄块并没有相对于body进行定位,当滚动条下拉时,小黄块定位固定在父元素左上角。



使用

fiexd元素一般用在如:to-top按钮,或者侧边悬浮面板,或者悬浮导航栏之中。



sticky 粘性定位

盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky对 table 元素的效果与 position: relative相同。



上面我们使用了fiexd与transform,发生了我们意想不到的效果,那就是fixed元素并未相对于body进行移动,也没有在父元素中进行标准的fixed定位。现在我们使用以下sticky属性来看一下效果。



<style>

        .box{

            box-sizing: border-box;

            height: 150px;

            border:solid 3px black;

            margin: 0 0 20px 0;

            overflow: auto;

        }

        .block{

            width: 50px;

            height: 50px;

            background-color: orange;

        }

        .sticky-1{

            position:sticky;

            top: 0px;

        }

    </style>

<div class="box box-1">

        <p>下面这个小黄块设置为sticky</p>

        <div class="sticky-1 block">



        </div>

        <p>

            hahah

        </p>

        <p>

            hahah

        </p>

        <p>hahaha</p>

        <p>hahaha</p>

    </div>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32



当我们向下滚动的时候神奇的事情发生了。







小黄块固定到了父元素的top:0位置了,不仅如此,再向上滑动后,小黄块又回复了当时的位置,而且占用了文档本身的位置。



使用这个特性我们可以制作浮动的Header组件,当用户向下滑动至窗口上侧的时候,Header组件也跟随窗口滑动。



Flex布局

对于前端工程师来说,最让人头疼的莫过于自适应布局。对于不同分辨率的设备要做到页面统一,在CSS3出现之前,还是挺不容易的。还有就是前端工程师头疼的一个布局问题:垂直居中。



CSS3中新出了一种布局技术:CSS弹性盒子布局,我们来看一下MDN是如何介绍的。



CSS 弹性盒子布局是 CSS 的模块之一,定义了一种针对用户界面设计而优化的 CSS 盒子模型。在弹性布局模型中,弹性容器的子元素可以在任何方向上排布,也可以“弹性伸缩”其尺寸,既可以增加尺寸以填满未使用的空间,也可以收缩尺寸以避免父元素溢出。子元素的水平对齐和垂直对齐都能很方便的进行操控。通过嵌套这些框(水平框在垂直框内,或垂直框在水平框内)可以在两个维度上构建布局。



接下来,我会使用Flex布局技术,设计一些我们常使用页面布局,并指出优点与缺点。但是,我们首先要来看一下浏览器的支持程度。



浏览器支持

特性 Firefox (Gecko) Chrome Internet Explorer Opera Safari

基础支持 20.0 (20.0) 21.0-webkit 29.0 10.0-ms 11.0 12.10 6.1-webkit

主流的浏览器全部支持Flex属性。注:与社会脱轨的IE9并不支持Flex,如果想写出兼容IE9的页面,请不要使用Flex。



Flex使用介绍

使用flex务必清楚一些属性概念。



Flex容器:对于一个基本元素(不含任何CSS属性,如div),设置display:flex,即可创建一个Flex容器。



Flex子项:父元素为Flex容器的元素,称之为Flex子项,其排布受到父元素影响。注:一定是父元素为Flex容器的元素,祖先不算。



排布方向:指Flex子项在Flex容器中的排布方向。排布方向有两种:column、row。在Flex容器上使用flex-direction: column|row(默认);即可设置。



主轴:指的Flex容器中是与排列方式相同的方向的轴。如设置Flex容器direction: column;则其主轴为竖直方向。



交叉轴:指的Flex容器中是与排列方式相反的方向的轴。如设置Flex容器direction: column;则其主轴为水平方向。



我们一定要清楚上面的基础概念,这对深入使用Flex有很大的帮助。下面我会介绍一些Flex常用的属性,主要分为两部分:对Flex容器、对Flex子项。



Flex容器属性

flex-direction 排布方向

flex-direction 属性指定了内部元素是如何在 flex 容器中布局的,定义了主轴的方向(正方向或反方向)。



flex-direction属性接受以下值:



row:子项目在flex容器中横向,从左至右排列。



row-reverse:表现和row相同,也是横向,但是是从右到左。



column:子项在容器中竖向排列,从上至下。

这里不贴图了

column-reverse:表现和column相同,子项在容器中竖向排列,从下至上。

这里不贴图了

flex-wrap 控制换行

CSS flex-wrap 指定 flex 元素单行显示还是多行显示 。如果允许换行,这个属性允许你控制行的堆叠方向。



取值:



nowrap(默认)

flex 的元素被摆放到到一行,这可能导致溢出 flex 容器。 cross-start 会根据 flex-direction 的值 相当于 start 或 before。

wrap

flex 元素 被打断到多个行中。cross-start 会根据 flex-direction 的值选择等于start 或before。cross-end 为确定的 cross-start 的另一端。



wrap-reverse

和 wrap 的行为一样,但是 cross-start 和 cross-end 互换。



flex-flow [排布方向/控制换行]的简称

CSS flex-flow 属性是 flex-direction 和 flex-wrap 的简写。



示例:flex-flow: column-reverse wrap;



justify-content 子项目在主轴上的排布

CSS justify-content 属性定义了浏览器如何分配顺着父容器主轴的弹性元素之间及其周围的空间。



justify-content同时受到父容器主轴的影响。



取值:



start



从行首开始排列。每行第一个元素与行首对齐,同时所有后续的元素与前一个对齐。



flex-start(默认)



从行首开始排列。每行第一个弹性元素与行首对齐,同时所有后续的弹性元素与前一个对齐。



flex-end



从行尾开始排列。每行最后一个弹性元素与行尾对齐,其他元素将与后一个对齐。



center



伸缩元素向每行中点排列。每行第一个元素到行首的距离将与每行最后一个元素到行尾的距离相同。



left



伸缩元素一个挨一个在对齐容器得左边缘,如果属性的轴与内联轴不平行,则left的行为类似于start



right



元素以容器右边缘为基准, 一个挨着一个对齐,如果属性轴与内联轴不平行,则right的行为类似于start.



space-between



在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首对齐,每行最后一个元素与行尾对齐。



space-around



在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素到行首的距离和每行最后一个元素到行尾的距离将会是相邻元素之间距离的一半。



space-evenly



flex项都沿着主轴均匀分布在指定的对齐容器中。相邻flex项之间的间距,主轴起始位置到第一个flex项的间距,主轴结束位置到最后一个flex项的间距,都完全一样。



看上去与space-around的排布很相似,但其实还是有一些区别的。space-evenly会在每一行均匀分布间隙,而space-around是均匀分布项目。

借一张图

看上去我们要学的属性很多,但是其实我们只需要记住我们常用的几个属性就行:flex-start、flex-end、space-between、center、space-around、space-evenly。以上这几个就是我们常用的属性值,通过设置主轴方向、设置排列方式,我们可以灵活地组织我们的元素。



align-items 子项目在交叉轴排布

CSS align-items属性将所有直接子节点上的align-self值设置为一个组。 align-self属性设置项目在其包含块中在交叉轴方向上的对齐方式。



取值:



normal



这个关键字的效果取决于我们处在什么布局模式中:在绝对定位的布局中,对于被替代的绝对定位盒子,这个效果和start的效果的一样;对于其他所有绝对定位的盒子,这个效果和stretch的效果一样。 在绝对定位布局的静态位置上,效果和stretch一样。对于那些弹性项目而言,效果和stretch一样。对于那些网格项目而言,效果和stretch一样,除了有部分比例或者一个固定大小的盒子的效果像start。这个属性不适用于会计盒子和表格。



flex-start



元素向侧轴起点对齐。



flex-end



元素向侧轴终点对齐。



center



元素在侧轴居中。如果元素在侧轴上的高度高于其容器,那么在两个方向上溢出距离相同。



因为align-items其实和justify-content我这里就不放一些图片凑字数了。



align-content 定义多根轴线排布

该属性对单行弹性盒子模型无效。(即:带有flex-wrap: nowrap)。



CSS的align-content属性设置了浏览器如何沿着伸缩盒子容器(flexbox container)的纵轴和网格容器(Grid Container)的主轴在内容项之间和周围分配空间。



它的取值和align-items差不多,经常有人会把他们搞混。



align-content一般定义多行的交叉轴排列。



绝大多数情况下我们使用align-items即可实现我们的需求。



Flex子项属性

order 子项排布靠前排名

CSS order 属性规定了弹性容器中的可伸缩项目在布局时的顺序。元素按照 order 属性的值的增序进行布局。拥有相同 order 属性值的元素按照它们在源代码中出现的顺序进行布局。







取值:



<integer>



表示此可伸缩项目所在的次序组。



flex-grow 子项放大比例

CSS flex-grow 属性定义弹性盒子项(flex item)的拉伸因子







取值:



<number>



默认值0,即如果存在剩余空间,也不放大。负值无效。



flex-shrink 子项缩小比例

CSS flex-shrink 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。







总而言之,你定了这个属性,其他项目会先压榨你的空间,然后再均匀缩小其他项目。



flex-basis

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



注:分配多余空间之前!!



也就是说你给的flex-basis值大于当前分配空间时,依然会被压缩。



flex

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



align-self

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



这个属性了不得,它也是我们经常用的子项目属性之一。



.item {

  align-self: auto | flex-start | flex-end | center | baseline | stretch;

}

1

2

3





就像上面的图,他可以决定子项目的交叉轴单独排列方式。



Grid 布局

未完待续…明天补上



参考

HTML5语义化标签属性-HTML5属性手册

All About Floats | CSS-Tricks

清除浮动的四种方式及其原理理解

【前端Talkking】CSS系列——CSS深入理解之absolute定位

CSS 弹性盒子布局

Flex 布局教程:语法篇

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档