diff 算法概述:
出处:https://coding.imooc.com/lesson/419.html#mid=33875
树 diff 的时间复杂度 O(n^3)
优化时间复杂度到O(n)
出处:https://coding.imooc.com/lesson/419.html#mid=33875
模板编译:
with 语法:
示例:不使用 with,对象里没有定义的属性为 undefined
const obj = {a: 100, b: 200}
console.log(obj.a) // 100
console.log(obj.b) // 200
console.log(obj.c) // undefined
使用 with,对象里没有定义的属性会报错
const obj = {a: 100, b: 200}
// 使用 with,能改变 {} 内自由变量的查找方式
// 将 {} 内自由变量,当作 obj 的属性来查找
with (obj) {
console.log(a) // 100
console.log(b) // 200
console.log(c) // Uncaught ReferenceError: c is not defined
}
模板编译:
示例:
(1)安装 vue-template-compiler
npm i vue-template-compiler --save
(2)创建 index.js 文件
const compiler = require('vue-template-compiler')
......
// 编译
const res = compiler.compile(template)
console.log(res.render)
(3)演示(以下演示均在 index.js 文件的 … 中)
插值:
// 插值
const template = `{{message}}
`
// with(this){return _c('p',['p',[_v(_s(message))]])}
// h -> vnode
// createElement -> vnode
表达式:
// 表达式
const template = `{{flag ? message : 'no message found'}}
`
//with(this){return _c('p',[_v(_s(flag ? message : 'no message found'))])}
属性和动态属性:
// 属性和动态属性
const template = `
`
// with(this){return _c('div',
// {staticClass:"container",attrs:{"id":"div1"}},
// [_c('img',{attrs:{"src":imgUrl}})]
// )}
条件:
// 条件
const template = `
A
B
`
// with(this){return _c('div',[(flag === 'a')?_c('p',[_v("A")]):_c('p',[_v("B")])])}
循环:
// 循环
const template = `
- {{item.title}}
`
// with(this){return _c('ul',_l((list),function(item){return _c('li',{key:item.id},[_v(_s(item.title))])}),0)}
事件:
// 事件
const template = `
`
// with(this){return _c('button',{on:{"click":clickHandler}},[_v("submit")])}
v-model:
// v-model
const template = ``
// 主要看 input 事件
// with(this){return _c('input',{directives:[{name:"model",rawName:"v-model",value:(name),expression:"name"}],attrs:{"type":"text"},domProps:{"value":(name)},on:{"input":function($event){if($event.target.composing)return;name=$event.target.value}}})}
编译模板:
Vue.component('heading', {
// template: `xxx`,
render: function (createElement) {
return createElement(
'h' + this.level,
[
createElement('a', {
attrs: {
name: 'headerId',
href: '#' + 'headerId'
}
}, 'this is a tag')
]
)
}
})
总结:
三大知识点:
三个过程:
<p>{{message}}</p>
export default {
data() {
return {
message: '杂货铺', // 会触发 get
city: '北京' // 不会触发 get,因为模板没用到,即和视图没关系
}
}
}
http://127.0.0.1:8881/01-hash.html?a=100&b=20#/aaa/bbb
location.protocol // 'http:' 【协议】
location.hostname // '127.0.0.1' 【IP地址/域名】
location.host // '127.0.0.1:8881' 【IP地址带端口】
location.port // '8881' 【端口】
location.pathname // '/01-hash.html' 【文件路径名】
location.search // '?a=100&b=20' 【参数】
location.hash // '#/aaa/bbb' 【#及后面的部分】
<p>hash test</p>
<button id="btn1">修改 hash</button>
// hash 变化,包括
// a. JS 修改 url
// b. 手动修改 url 的 hash
// c. 浏览器前进、后退
window.onhashchange = (event) => {
console.log('old url', event.oldURL)
console.log('new url', event.newURL)
console.log('hash', location.hash)
}
// 页面初次加载,获取 hash
document.addEventListener('DOMContentLoaded', () => {
console.log('hash:', location.hash)
})
// JS 修改 url
document.getElementById('btn1').addEventListener('click', () => {
location.href = '#/user'
})
<p>history API test</p>
<button id="btn1">修改 url</button>
// 页面初次加载,获取 path
document.addEventListener('DOMContentLoaded', () => {
console.log('load', location.pathname)
})
// 打开一个新的路由
// 【注意】用 pushState 方式,浏览器不会刷新页面
document.getElementById('btn1').addEventListener('click', () => {
const state = {name: 'page1'}
console.log('切换路由到', 'page1')
history.pushState(state, '', 'page1')
})
// 监听浏览器前进、后退‘
window.onpopstate = (event) => {
console.log('onpopstate', event.state, location.pathname)
}
不积跬步无以至千里,不积小流无以成江海
点个关注不迷路,持续更新中…