Directorio de artículos de la serie
Directorio de artículos
1. Descripción general del DOM virtual - algoritmo diff
Enlace de referencia del algoritmo de diferencias
- El algoritmo diff es la parte central y más crítica de vdom
- El algoritmo diff se puede reflejar en el uso diario de vue react (como key)
Descripción general del algoritmo diff:
- diff es contraste, que es un concepto amplio, como el comando linux diff, el comando git diff
- Dos objetos js también pueden hacer diferencias.
- Dos árboles hacen diferencias, como vdom diff aquí
Fuente: https://codificación.imooc.com/lesson/419.html#mid=33875
La complejidad temporal de la diferencia del árbol es O(n^3)
- Primero, atraviesa el árbol1
- Segundo, atravesar tree2
- Tercero, ordenar
- 100 nodos, para calcular 1 millón de veces, el algoritmo no está disponible
Optimizar la complejidad del tiempo a O(n)
- Compare solo el mismo nivel, no entre niveles
- Si las etiquetas no son las mismas, elimine y reconstruya directamente, y ya no compare en profundidad
- Si la etiqueta y la clave son iguales, se considera que son el mismo nodo y no se requiere ninguna comparación adicional.
Fuente: https://codificación.imooc.com/lesson/419.html#mid=33875
2. Compilación de plantillas
1. Compilación de plantillas - con sintaxis
- Las plantillas son la parte más utilizada del desarrollo de vue, es decir, los principios asociados con el uso
- No es html, tiene directivas, interpolación, expresiones JS, ¿qué diablos es?
Compilación de plantillas:
- Requisitos previos: JS con sintaxis
- vue template complier compila plantillas en funciones de renderizado
- Ejecute la función render para generar vnode
con sintaxis:
- Cambie las reglas de búsqueda para variables libres en {}, como atributos obj para buscar
- Si no se encuentra ninguna propiedad obj coincidente, se informará un error
- with debe usarse con precaución, rompe las reglas de alcance y es poco legible
Ejemplo: Sin con, la propiedad indefinida en el objeto es indefinida
const obj = {
a: 100, b: 200}
console.log(obj.a) // 100
console.log(obj.b) // 200
console.log(obj.c) // undefined
Usando with, la propiedad que no está definida en el objeto reportará un error
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
}
2. ¿En qué se compila la plantilla vue?
Compilación de plantillas:
- La plantilla no es html, tiene instrucciones, interpolación y expresiones JS, que pueden realizar juicios y bucles.
- HTML es un lenguaje de etiquetas, solo JS puede realizar juicios y bucles
- Por lo tanto, la plantilla debe convertirse en algún tipo de código JS, es decir, compilación de plantilla
Ejemplo:
(1) Instalaciónvue-plantilla-compilador
npm i vue-template-compiler --save
(2) Cree el archivo index.js
const compiler = require('vue-template-compiler')
......
// 编译
const res = compiler.compile(template)
console.log(res.render)
(3) Demostración (las siguientes demostraciones están en el archivo index.js...)
Interpolar:
- El resultado de la impresión es: cree una etiqueta p, el elemento secundario es TextVNode, que es una cadena
- _c: crearElemento, crear elemento
- _v: createTextVNode, crea un nodo de texto
- _s: toString, convertir a tipo de cadena
- esto: const vm = new Vue({…}), que es la instancia de vm
// 插值
const template = `<p>{
{message}}</p>`
// with(this){return _c('p',['p',[_v(_s(message))]])}
// h -> vnode
// createElement -> vnode
expresión:
- Las expresiones en la plantilla se ejecutan como código JS
// 表达式
const template = `<p>{
{flag ? message : 'no message found'}}</p>`
//with(this){return _c('p',[_v(_s(flag ? message : 'no message found'))])}
Propiedades y propiedades dinámicas:
- contenedor, div1 es una cadena estática, por lo que debe estar entre comillas después de la compilación
- imgUrl es un atributo dinámico y una variable, por lo que no está entre comillas después de la compilación
// 属性和动态属性
const template = `
<div id="div1" class="container">
<img :src="imgUrl"/>
</div>
`
// with(this){return _c('div',
// {staticClass:"container",attrs:{"id":"div1"}},
// [_c('img',{attrs:{"src":imgUrl}})]
// )}
condición:
- Convertir a una expresión ternaria
// 条件
const template = `
<div>
<p v-if="flag === 'a'">A</p>
<p v-else>B</p>
</div>
`
// with(this){return _c('div',[(flag === 'a')?_c('p',[_v("A")]):_c('p',[_v("B")])])}
ciclo:
- _l: renderList, lista de renderizado
- La segunda devolución, el primer parámetro devuelto es la etiqueta, el segundo parámetro es el atributo y el tercer parámetro es el elemento secundario
// 循环
const template = `
<ul>
<li v-for="item in list" :key="item.id">{
{item.title}}</li>
</ul>
`
// with(this){return _c('ul',_l((list),function(item){return _c('li',{key:item.id},[_v(_s(item.title))])}),0)}
evento:
- Hay un evento en on, y el nombre de la función es una variable, sin comillas.
// 事件
const template = `
<button @click="clickHandler">submit</button>
`
// with(this){return _c('button',{on:{"click":clickHandler}},[_v("submit")])}
v-modelo:
// v-model
const template = `<input type="text" v-model="name">`
// 主要看 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}}})}
Compile la plantilla:
- La plantilla se compila en una función de representación y la función de representación se ejecuta para devolver el vnode
- Ejecutar parche y diff basado en vnode
- Usando webpack vue-loader, la plantilla se compilará en el entorno de desarrollo
3. Use render en lugar de plantilla en componentes vue
- En algunos casos complejos, no se puede usar la plantilla y se puede considerar el renderizado.
- React siempre ha usado render (sin plantillas)
Vue.component('heading', {
// template: `xxx`,
render: function (createElement) {
return createElement(
'h' + this.level,
[
createElement('a', {
attrs: {
name: 'headerId',
href: '#' + 'headerId'
}
}, 'this is a tag')
]
)
}
})
Resumir:
- con sintaxis
- Plantilla para renderizar función, para vnode, para renderizar y actualizar
- Los componentes de Vue pueden usar render en lugar de plantilla
4. Resumir el proceso de renderizado/actualización del componente
- Un componente se representa en la página, la modificación de los datos desencadena una actualización (vista basada en datos)
- ¿Cuál es la lógica detrás de esto y qué puntos deben dominarse?
- Examinar la exhaustividad de la comprensión del proceso.
Tres puntos de conocimiento:
- Responsivo: escuche el setter de getter de propiedad de datos
- Compilación de plantillas: plantilla para representar la función, luego para vnode
- vdom:parche(elemento,vnodo) 和 parche(vnodo, nuevoVnodo)
Tres procesos:
- Proceso de renderizado inicial
- proceso de actualización
- Representación asíncrona
3. Cómo se procesan y actualizan los componentes de vue
1. El proceso de renderizado inicial
- Analice la plantilla en una función de representación (o completada en el entorno de desarrollo, vue-loader)
- Disparador receptivo, escuche el setter de obtención de propiedades de datos
- Ejecute la función render para generar vnode, patch(elem, vnode)
2. Ejecutar la función de renderizar activará el getter
- Los que se usan en la plantilla activarán obtener
- Los que no se usan en la plantilla no activarán la obtención, porque no tienen nada que ver con la vista.
<p>{
{
message}}</p>
export default {
data() {
return {
message: '杂货铺', // 会触发 get
city: '北京' // 不会触发 get,因为模板没用到,即和视图没关系
}
}
}
3. Proceso de actualización
- Modifique los datos y active el setter (se ha monitoreado antes en el getter)
- Vuelva a ejecutar la función render para generar newVnode
- parche(vnodo, nuevoVnodo)
4. Cómo renderizar de forma asíncrona con componentes vue
- $nextTick es asíncrono
- Resuma la modificación de datos y actualice la vista al mismo tiempo
- Reduzca el número de operaciones DOM y mejore el rendimiento
4. Cómo implementar el enrutamiento hash con JS
- El modo de enrutamiento de vue-router: modo hash, historial H5
1. Componentes de la URL de una página web
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' 【#及后面的部分】
2. Características del hachís
- Los cambios hash activarán saltos de página web, es decir, el navegador hacia adelante y hacia atrás
- Los cambios hash no actualizarán la página, una característica necesaria de SPA
- El hash nunca se enviará al lado del servidor (el front-end se las arreglará solo)
3. Ejemplo de cambio de hash
- onhashchange: se usa para monitorear cambios en los valores hash
- El atributo href es una cadena legible y escribible que establece o devuelve la URL completa del documento que se muestra actualmente.
<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'
})
5. Cómo implementar el enrutamiento de historial H5 con JS
- Ruta con especificación de URL, pero no actualice la página al saltar
- historia.pushState
- ventana.onpopstate
1. Ejemplo
- history.pushState(estado,título,url)
- estado: un objeto de estado relacionado con la URL especificada. Cuando se activa el evento popstate, el objeto se pasará a la función de devolución de llamada. Si no necesita este objeto, puede completar nulo aquí
- título: el título de la nueva página, pero todos los navegadores actualmente ignoran este valor, por lo que puede completar nulo aquí
- url: La nueva URL, que debe estar en el mismo dominio que la página actual. La barra de direcciones de su navegador mostrará esta URL
<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)
}
2. Cómo elegir
- Se recomienda que los sistemas B (para empresas o grupos de usuarios específicos) usen hash, que es fácil de usar e insensible a las especificaciones de URL
- Para el sistema C (para consumidores individuales), puede considerar elegir el historial H5, pero necesita soporte del servidor
- Puede elegir simple, no usar complejo, considerar costo y beneficio
不积跬步无以至千里,不积小流无以成江海
Pulsa para seguir y no te pierdas, sigue actualizando...