display:table && display:table-cell 实现布局

我们都知道css3支持flex布局,可以实现水平和垂直居中的场景。但是对于老的浏览器可能不支持flex属性,我们可以通过display: tabledisplay: table-cell来布局。

代码片段如下:

.container {
   /* display: flex;
    align-items: center;*/
    display: table;
    width: 100%;
    height: 200px;
    background-color: red;
}

.block {
    display: table-cell;
    vertical-align: middle;
    width: 50%;
}
<div class="container">
    <div class="block">
        <h1>hello</h1>
        <span>world</span>
    </div>
    <div class="block">
        <h1>Shit</h1>
        <span>HaHa</span>
    </div>
</div>

Vue SSR 基本用法

安装

npm install vue vue-server-renderer --save

1. 渲染一个 Vue 实例

新建文件vue-demo.js

// 第 1 步:创建一个 Vue 实例
const Vue = require('vue')
const app = new Vue({
  template: `<div>Hello World</div>`
})

// 第 2 步:创建一个 renderer
const renderer = require('vue-server-renderer').createRenderer()

// 第 3 步:将 Vue 实例渲染为 HTML
renderer.renderToString(app, (err, html) => {
  if (err) throw err
  console.log(html)
  // => <div data-server-rendered="true">Hello World</div>
})

// 在 2.5.0+,如果没有传入回调函数,则会返回 Promise:
renderer.renderToString(app).then(html => {
  console.log(html)
}).catch(err => {
  console.error(err)
})

需要在node环境下运行

node vue-demo.js

2. 与服务器Express集成

npm install express --save

新建文件express-server.js

const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()

server.get('*', (req, res) => {
  const app = new Vue({
    data: {
      url: req.url
    },
    template: `<div>visit URL is {{ url }}</div>`
  })

  renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.end(`
      <!DOCTYPE html>
      <html lang="en">
        <head><title>Hello inner HTML</title></head>
        <body>${html}</body>
      </html>
    `)
  })
})

server.listen(8080)
node express-server.js

3. 从文件中读取模版,取代字符串模版

当你在渲染 Vue 应用程序时,renderer 只从应用程序生成 HTML 标记 (markup)。在这个示例中,我们必须用一个额外的 HTML 页面包裹容器,来包裹生成的 HTML 标记。

为了简化这些,你可以直接在创建 renderer 时提供一个页面模板。多数时候,我们会将页面模板放在特有的文件中
index.template.html

<!DOCTYPE html>
<html lang="en">
  <head><title>Hello outer HTML</title></head>
  <body>
    <!--vue-ssr-outlet-->
  </body>
</html>

注意 注释 — 这里将是应用程序 HTML 标记注入的地方。

vue-tpl.html

<div>vue-tpl.html => visit URL is {{ url }} </div>

express-server2.js

const Vue = require('vue')
const server = require('express')()

const renderer = require('vue-server-renderer').createRenderer({
  template: require('fs').readFileSync('./index.template.html', 'utf-8')
})

server.get('*', (req, res) => {
  const app = new Vue({
    data: {
      url: req.url
    },
    template: require('fs').readFileSync('./vue-tpl.html', 'utf-8')
  })


  renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.end(html)
  })


})

server.listen(8080)

4. 模板插值

index.template3.html

<!DOCTYPE html>
<html lang="en">
  <head><title>{{ title }}</title></head>
  <body>
    <div>1</div>
    <!--vue-ssr-outlet-->
    <div>2</div>
  </body>
</html>

express-server3.js

const Vue = require('vue')
const server = require('express')()

const renderer = require('vue-server-renderer').createRenderer({
  template: require('fs').readFileSync('./index.template3.html', 'utf-8')
})

server.get('*', (req, res) => {
  const app = new Vue({
    data: {
      url: req.url
    },
    template: `<div>visit URL is {{ url }} </div>`
  })

  const context = {
    title: 'variable title',
  }

  renderer.renderToString(app, context, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.end(html)
  })


})

server.listen(8080)

也可以与 Vue 应用程序实例共享 context 对象,允许模板插值中的组件动态地注册数据。

此外,模板支持一些高级特性,例如:

  • 在使用 *.vue 组件时,自动注入「关键的 CSS(critical CSS)」;
  • 在使用 clientManifest 时,自动注入「资源链接(asset links)和资源预加载提示(resource hints)」;
  • 在嵌入 Vuex 状态进行客户端融合(client-side hydration)时,自动注入以及 XSS 防御。

Promise的几个代码片段

片段1

<script>
        var p1 = new Promise(function(resolve, reject) {
            resolve(1)
        })

        var p2 = Promise.reject(2)

        // 异步1
        p2.then(function(value) {
            console.log('doo1')
        }, reason => {
            setTimeout(function() {
                 console.log('doo111111111111111') // [最后]
            }, 2000)

            console.log('doo11') // [1]

        }).then(value => {
            console.log('doo1111') // [4]
        }, value => {
            console.log('doo111')
        }).then(value => {
            console.log('doo11111') // [6]
        }, value => {
            console.log('doo111111')
        })

        // 异步2
        p2.catch(function(reason) {
            console.log('catch()' + reason) // [2]
            // return Promise.reject()
        }).then(value => {
            console.log('doo0') // [5]
        }, value => {
            console.log('doo00')
        })


        // 异步3
        p2.then(function(value) {
            console.log('doo2')
        }, reason => {
            console.log('doo22') // [3]
        })


        // Promise.all([p1, p2]).then(function(value) {
        //     console.log('onResolved()' + value)
        // }, function(reason) {
        //     console.log('onRejected()' + reason)
        // })
    </script>

异步1 异步2 异步3这个3组链式调用,是并行调用的,彼此之间不关联。

片段2

 <script>
        var p1 = new Promise(function(resolve, reject) {
            resolve('Rick')
        })

        setTimeout(() => {
            p1.then(value => {
                console.log('hello: ' + value) // 后指定回调函数
            })
        }, 1000)
    </script>

可以在resolve之后,再声明then

片段3

 <script>
        console.log('-----------')

        var p = Promise.reject(100)

        p.then(value => {}, reason => {
            console.log('---onRejected: ' + reason)
        }).catch(error => {
            console.log('---catch: ' + error) // 被then中的onRejected处理,catch就不会再执行
        })

        p.then(value => {}).catch(error => {
            console.log('---22222222catch: ' + error) // catch会再执行
        })

    </script>

如果在then中的oneRejected中处理了,就不会在catch中处理了。处理后,不抛出异常或rejected,下一个then将会执行onResolved

ES this的问题

浏览器环境

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>this</title>
</head>
<body>
    <script>
        var age = 100
        var rick = {
            age: 30,
            name: 'Rick',
            grow() {
                console.log(`I am ${this.name}, I am ${this.age}`) // age: 30
                setTimeout(function() {
                    console.log(`I am ${this.age}`) // 100
                    console.log(`I am ${window.age}`) // 100
                    console.log(`I am ${age}`) // 100
                    console.log(window === this) // true
                }, 100)

            }
        }

        rick.grow()

        function testThis(param) {
            console.log(param + '. this === window => ' +  (this === window))
        }

        testThis(1) // 作为一个函数的话 this指向global,浏览器环境下就是window
        new testThis(2) // 作为一个对象的话 this指向对象

    </script>
</body>
</html>

node环境

// let age = 100;
age = 100

let rick = {
    age: 30,
    name: 'Rick',
    grow() {
        // console.log(`I am ${this.name}, I am ${this.age}`) // age: 30
        setTimeout(function() {
            console.log(`I am ${this.age}`) // 使用bind(this) age: 30. 否则this函数自身的this
            // console.log(this)

            // for (let k in this) {
            //     console.log(k)
            // }
        }.bind(this), 1001)

    }
}

// rick.grow()

// 数组复制
let a = [1, 2]
let b = [...a]
console.log(b)

// 对象复制
let user = {
    name: 'Jame'
}

let c = Object.assign({}, user) 
console.log(c)
let d = {...user}
console.log(d)

// 数组转函数参数
function test(a, b) {
    console.log(`a: ${a}, b: ${b}`)
    console.log(`2.this => ${this}`)
}
console.log(test(...a))
console.log(test.apply(null, a)) // apply的作用

console.log(`1.this => ${this}`)

history.pushState的用处

以前做后台管理的时候,采用的是ajax+iframe,导致的问题是“刷新”就会回到首页,采用html5的history.pushState可以更好的完成,项目pajx就是封装了history和ajax的功能

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
</head>
<body>
    <button id="btn">click</button>

    <a id="a" href="http://www.baidu.com" target="_self">baidu</a>

    <script>
        document.getElementById('btn').onclick = function() {
            var title = '新的页面'
            history.pushState(null, null, "line.html");

            document.title = title

            return false;
        }

        document.getElementById('a').onclick =  function () {
            console.log('...jump')

            // 可以阻止链接跳转
            return false
        }
    </script>
</body>
</html>

https://www.zhangxinxu.com/wordpress/2013/06/html5-history-api-pushstate-replacestate-ajax/