runtime-only 和 runtime-compiler
-
runtime-only:是运行的时候代码不能包含任意一个template标签
render(h)- 》 virtual Dom - 》UI真实dom
我们在使用 Runtime Only 版本的 Vue.js 的时候,通常需要借助如 webpack 的 vue-loader 工具把 .vue 文件编译成 JavaScript,因为是在编译阶段做的,所以它只包含运行时的 Vue.js 代码,因此代码体积也会更轻量。 在将 .vue 文件编译成 JavaScript的编译过程中会将组件中的template模板编译为render函数,所以我们得到的是render函数的版本。所以运行的时候是不带编译的,编译是在离线的时候做的。
-
runtime-compiler:代码中可以有template标签
-
template加载过程:
template - 》parse - 》ast 抽象语法树 - 》compiler - 》render(h)- 》 virtual Dom - 》UI真实dom
-
总结对比
最终渲染都是通过 render 函数,如果写 template 属性,则需要编译成 render 函数,那么这个编译过程会发生运行时,所以需要带有编译器的版本。
很显然,这个编译过程对性能会有一定损耗,所以通常我们更推荐使用 Runtime-Only 的 Vue.js。
runtime-only比runtime-compiler性能更高,代码更少(少6kb)
计算属性和监听属性和方法的区别
计算属性
计算属性是依赖的值改变会重新执行函数,当数据没有变化的时候,他会读取缓存。计算属性是取返回值作为最新结果,所以里面不能异步的返回结果。不能写异步逻辑。
页面初次加载的时候,会运行计算
计算属性是对多个属性进行监听,进一步整合,执行判断逻辑等,返回结果作为一个新的属性,可以绑定在页面中
监听属性
侦听属性是侦听的值改变会重新执行函数,将一个值重新赋值作为最新结果,所以赋值的时候可以进行一些异步操作。
页面初次加载的时候,不会执行操作
监听属性 是对单个已存在的data属性进行监听,获取 oldValue newValue,然后执行一些判断逻辑,比如修改其他值
总结对比
computed是属性调用,而method是函数调用
数据变化时执行异步或者开销比较大的操作的时候,这时候使用watch是合适的
computed一般是一个依赖值衍生新的值,值结果会被缓存,除非依赖值发生变化才会重新计算( eg:购物车结算 )
watch一般监听一个对象键值是需要观察的变量或者表达式,键值对应是回调函数,主要是负责监听某些特定数据的变化,从而进行某些具体的业务逻辑
methods方法表示一个具体的操作,负责书写主要业务逻辑
keep-alive
名词解释和作用
keep-alive是vue内置的组件,自身不会渲染一个DOM元素,Vue在初始化生命周期的时候,为组件实例建立父子关系会根据abstract属性决定是否忽略某个组件。在keep-alive中,设置了abstract:true,那Vue就会跳过该组件实例。最后构建的组件树中就不会包含keep-alive组件,那么由组件树渲染成的DOM树自然也不会有keep-alive相关的节点了。
可以是被包含的组件保留状态,缓存组件实例,不会销毁,避免重新渲染。
避免组件反复创建和渲染,有效提升系统性能。总的来说,keep-alive用于保存组件的渲染状态。
对应的vue组件生命周期 activited和deactivited
属性说明
include:可以是字符串(组件名称)或者正则表达式,只有匹配的组件会被缓存
exclude:可以是字符串(组件名称)或者正则表达式,任何匹配的组件都不会被缓存
max:定义缓存组件上限,超出上限使用LRU的策略置换缓存数据。
内存管理的一种页面置换算法,对于在内存中但又不用的数据块(内存块)叫做LRU,操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据。
两个同时使用,若某组件同时被两个属性都匹配, exclude 优先级较高,最终匹配的组件不会被缓存
路由传参
路由传参有4种方式
路由配置表中,路径后面串联传入的参数
强制刷新页面,参数不会丢失 {path: '/a/:num', name: A, component: A}
方式1:通过router-link,to属性 路由地址+传递参数
<router-link to = "/a/12">
方式2:通过path 串联路由地址和传递的参数
this.$router.push({
path: `/d/${id}`
})
方式3:通过命名路由+params 匹配路由配置好的属性名
this.$router.push({
name: 'A',
params: {
num: '12'
}
})
命名路由+params传递参数
路径后面不需要加传入的参数,再次刷新页面后,参数会丢失 {path: '/b', name: 'B', component: B}
this.$router.push({
name: 'B',
params: {
sometext: '一只羊出没'
}
})
获取参数: {{this.$route.params.sometext}}
通过query来传递参数
会显示在地址,以?开头串联在地址末尾,传递多个参数,用“&”隔开,每个参数的名和值用“=”隔开,强制刷新页面,参数不会丢失
this.$router.push({
path: '/c',
query: {
sometext: '这是小羊同学'
}
获取参数:{{this.$route.query.sometext}}
传参注意事项
1.当使用path路径匹配路由时,不能和params不能同时使用,params传递的参数会丢失
2.当使用命名路由时name,params和query可以同时使用传递参数
路由懒加载
为什么要懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。
路由中会定义很多不同的页面,默认情况下这些页面会被打包放在一个js文件中,造成这个js文件非常大,请求耗时会比较久,有可能用户的电脑还会出现短暂的空白,影响用户的体验。
怎么实现懒加载
结合 Vue 的异步组件 (opens new window)和 Webpack 的代码分割功能 (opens new window),轻松实现路由组件的懒加载
路由懒加载功能
主要作用就是将路由对应的组件打包成一个个的js代码块,只有在这个路由被访问的时候,才加载对应的组件
路由懒加载的三种方式
方式1 结合vue的异步组件和webpack的代码分析,写法太复杂,基本已经弃用
const home = resolve => {require.ensure(['../views/Home.vue'],()=>{
resolve(require('../views/Home.vue'))
})}
方式2:AMD写法,也基本被弃用了
const home = resolve =>require(['../vuews/Home.vue'],resolve);
方式3:在ES6中 有更加简单的写法来组织vue异步组件和webpack的代码分割,强烈推荐
const home = ()=> import('../views/Home.vue')
路由守卫
路由守卫分为2两种: 全局守卫和局部守卫
全局守卫 :前置守卫 beforeEatch 和后置钩子 afterEatch
局部守卫包括:路由守卫和组件守卫
路由守卫是配置在路由映射表中,beforeEnter,参数和beforeEatch一直,优先级高于全局守卫
组件守卫是定义在组件中的钩子函数 beforeRouterEnter , beforeRouterUpdate, beforeRouterLevel
beforeRouterEnter 中不能使用this,因为还没有创建好组件。
beforeRouterUpdate 是当路由地址没有改变,但是参数改变的时候,才会被调用,比如 /a/1 => /a/2
beforeEatch((to,from,next)={
})
beforeEatch是一个函数,里面的参数是一个箭头函数,to和from 都是route对象实例,next和函数,必须要调用,所以不会执行路由不会跳转
通常用全局的守卫来监听路由跳转,执行一些全局的操作,比如标题。
路由导航
所有的组件都继承自vue的原型,在vue原型vue.prototype 上定义的函数和属性,子组件可以通过this. 直接调用,
比如**this.$router 和this.$route**
this.$router 指向的路由映射表,VueRouter实例,可以导航到不同的url,
this.$router.push(),this.$router.replace,对应的history中的pushState和replaceState
this.$route 指向的是路由映射表中的一个路由选项,代表当前跳转的路由,可以获取当前路由的name,path,query,params等
Es6新特性
1.不一样的变量声明:const和let,ES6推荐使用let声明局部变量
let表示声明变量,而const表示声明常量,两者都为块级作用域;const 声明的变量都会被认为是常量,意思就是它的值被设置完成后就不能再修改了
如果const的是一个对象,对象所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的地址没有变就行
let 关键词声明的变量不具备变量提升(hoisting)特性,不能先使用,再声明。var具备变量提升
let 和 const 声明只在最靠近的一个块中(花括号内)有效
当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING
const 在声明时必须被赋值
2.模板字符串
在ES6之前,我们往往通过“\”和“+”来构建模板
es6可以将表达式嵌入字符串中进行拼接。用${}来界定;
ES6反引号(``)直接搞定;
$("body").html(`This demonstrates the output of HTML content to the page, including student's ${name}, ${seatNumber}, ${sex} and so on.`);
3.箭头函数(Arrow Functions)
ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体;
箭头函数最直观的三个特点。
- 不需要 function 关键字来创建函数
- 省略 return 关键字
- 继承当前上下文的 this 关键字
- 当你的函数有且仅有一个参数的时候,是可以省略掉括号的。当你函数返回有且仅有一个表达式的时候可以省略{} 和 return;
4.函数参数默认值
// ES6之前,当未传入参数时,
text = 'default';
function printText(text) {
text = text || 'default';
console.log(text);
}
// ES6;
function printText(text = 'default') {
console.log(text);
}
printText('hello'); // helloprintText();// default
5.二进制和八进制字面量
ES6 支持二进制和八进制的字面量,通过在数字前面添加 0o 或者0O 即可将其转换为八进制值:
let oValue = 0o10;console.log(oValue); // 8 let bValue = 0b10; // 二进制使用 `0b` 或者 `0B`console.log(bValue); // 2
6.模块化 export 和 import
import 导入模块、export 导出模块
可以直接在任何变量或者函数前面加上一个 export 关键字,就可以将它导出。
let var 和const区别
在javascript中有三种声明变量的方式:var、let、const。
JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域。****块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
var
var定义的变量可以修改,如果不初始化会输出undefined,不会报错。
var 声明全局变量,换句话理解就是,声明在for循环中的变量,跳出for循环同样可以使用。
let
同一个变量,不可在声明之前调用,必须先定义再使用,否则会报错,循环体中可以用let
let是块级作用域,函数内部使用let定义后,对函数外部无影响。并且let不能定义同名变量,否则会报错。
cosnt
const:用于声明常量,也具有块级作用域 ,也可声明块级。const定义的变量不可以修改,而且必须初始化。
如果const的是一个对象,对象所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的地址没有变就行
它和let一样,也不能重复定义同一个变量,const一旦定义,无法修改.
let和const属于局部变量,不会出现变量提升的情况,
全局定义的let和const变量,不属于顶层变量,不属于window的属性,
浏览器环境中顶层对象是window,Node中是global对象
es5中顶层变量的属性等价于全局变量,定义的var变量是window属性
到了es6中有所改变,es5的var ,function 声明的全局变量 依旧是顶级对象的属性 而es6声明的全局变量不属于顶级对象的属性了
var age = 29;
let ages = 29;
alert(window.age) ==>29
alert(window.ages ) ==>undefined
axios配置
//安装axios
npm install axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。可以执行get请求,执行post请求,执行多个并发请求,支持promise ,拦截请求和响应,转换请求数据和响应数据,取消请求 ,自动转换json数据。
1.支持node端和浏览器端
同样的API,node和浏览器全支持,平台切换无压力
2.支持 Promise
使用Promise管理异步,告别传统callback方式
3.丰富的配置项
支持拦截器等高级配置
常用的请求配置
method:请求方法 post get delete put等
baseUrl:请求基本路径地址,将自动加在 `url` 前面
url:请求地址
headers:自定义请求头参数,可以包含token,content-type等
timeout:配置请求超时
params: 是即将与请求一起发送的 URL 参数
添加拦截器
// 添加请求拦截器
axios.interceptors.request.use(
function (response) { // 对请求数据做点什么 return response; },
function (error) { // 对请求错误做点什么 return Promise.reject(error); }
);
// 添加响应拦截器
axios.interceptors.response.use(
function (response) { // 对响应数据做点什么 return response; },
function (error) { // 对响应错误做点什么 return Promise.reject(error); }
);
创建axios实例
function createAxios(type){
let timeout = 20000; //统一的超时时间
var token = null;
if (userInfo.token()) {
token = userInfo.token();
}
let applicationHeaderPayload = {
'Content-Type': 'application/json; charset=utf-8',
'token':token,
'platform': "H5",
'Accept': '*/*'
}
let applicationHeader = {
'Content-Type': 'application/x-www-form-urlencoded',
'token':token,
'platform': "H5",
'Accept': '*/*'
};
let args = {}; //配置参数
let axiosInstance; //axios 实例
switch(type){
case "payload" :
args = {
timeout,
"headers": applicationHeaderPayload
};
break;
case "formData" :
args = {
timeout,
"headers" : applicationHeader
};
break;
default :
break;
}
axiosInstance = axios.create(args);
axiosInstance.interceptors.request.use (function (config) { //请求拦截器
var token = null;
if (userInfo.token()) {
token = userInfo.token();
}
config.url = baseUrl+config.url;
config.headers = {
'Content-Type': 'application/json; charset=utf-8',
'token':token,
'platform': "H5",
'Accept': '*/*'
}
if(config && config.data && ['formData'].indexOf(type) != -1){
config.data = qs.stringify(config.data);
config.headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'token':token,
'platform': "H5",
'Accept': '*/*'
}
}
return config;
}, function (error) {
return Promise.reject(error);
});
axiosInstance.interceptors.response.use(function (response) { //返回拦截器
return handleSuccess(response);
}, function (data) {
return handleError(data);
});
return axiosInstance;
}
vue-router两种加载模式
1. Hash (对应HashHistory)
hash(“#”)符号的本来作用是加在URL中指示网页中的位置:
http://www.example.com/index.html#print
符号本身以及它后面的字符称之为hash(也就是我之前为什么地址栏都会有一个‘#’),可通过window.location.hash属性读取。它具有如下特点:
- hash虽然出现在URL中,但不会被包括在HTTP请求中。它是用来指导浏览器动作的,对服务器端完全无用,因此,改变hash不会重新加载页面
2.可以为hash的改变添加监听事件:
window.addEventListener("hashchange", funcRef, false)
- 每一次改变hash(window.location.hash),都会在浏览器的访问历史中增加一个记录
利用hash的以上特点,就可以来实现前端路由“更新视图但不重新请求页面”的功能了。
2. History (对应HTML5History)
History接口是浏览器历史记录栈提供的接口,通过back(), forward(), go()等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。
从HTML5开始,History interface提供了两个新的方法:pushState(), replaceState()使得我们可以对浏览器历史记录栈进行修改:
window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)
stateObject: 当浏览器跳转到新的状态时,将触发popState事件,该事件将携带这个stateObject参数的副本
title: 所添加记录的标题
URL: 所添加记录的URL
这两个方法有个共同的特点:当调用他们修改浏览器历史记录栈后,虽然当前URL改变了,但浏览器不会刷新页面,这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础。
浏览器历史记录可以看作一个「栈」。栈是一种后进先出的结构,可以把它想象成一摞盘子,用户每点开一个新网页,都会在上面加一个新盘子,叫「入栈」。
用户每次点击「后退」按钮都会取走最上面的那个盘子,叫做「出栈」。而每次浏览器显示的自然是最顶端的盘子的内容。
vue-router 的作用
vue-router的作用就是通过改变URL,在不重新请求页面的情况下,更新页面视图。简单的说就是,虽然地址栏的地址改变了,但是并不是一个全新的页面,而是之前的页面某些部分进行了修改。
export default new Router({
mode: 'history', //后端支持可开
routes: constantRouterMap})
这是Vue项目中常见的一段初始化vue-router的代码,mode属性用来指定vue-router使用哪一种模式。在没有指定mode的值,则使用hash模式。
vue-router路由模式有几种?请谈谈你对它们的理解?
常用的路由模式有hash和history;
最直观的区别是hash模式url上会携带有一个#,而history不携带;
hash:
即地址栏URL中的#符号,它的特点在于hash值虽然出现在URL中,但不会被包括在HTTP请求中,对服务端完全没影响,因此改变hash值不会重新加载页面。
history:
利用了HTML5 History interface 中新增的pushState() 和 replaceState()方法。
这两个方法应用于浏览器历史记录栈,提供了修改历史记录的功能,执行修改时虽然改变了URL但是不会立即的向服务端发起请求。
hash和history模式都属于浏览器自身的特性,vue-router只是利用了这两个特性来实现前端路由
但是在history模式下会出现刷新404的问题,对于这个问题,我们只需要在服务器配置nginx如果URL匹配不到任何静态资源,就跳转到默认的index.html
history.pushState()相比于直接修改hash主要有以下优势:
- pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL
- pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中
- pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串
- pushState可额外设置title属性供后续使用
v-if 和 show的区别
相同点:v-if与v-show都可以动态控制dom元素显示隐藏
不同点:v-if显示隐藏是将dom元素整个添加或删除,而v-show隐藏则是为该元素添加css--display:none,dom元素还在。
组件通信的方法
父子组件通信
1.props 父组件向子组件传递数据 ,$emit 子组件触发父组件事件响应
2.$children 和 $refs 获取子组件实例对象,$parent或者$root 获取父组件或者根组件实例对象。拿到实例对象可以直接操作data数据或者调用函数,但是一般不推荐,耦合度太高
$children 和 $refs 获取子组件实例对象 这两个的区别:
ref可以指定任意的dom元素节点,包括原生HTML元素,children 获取的是包含自定义子组件实例列表,并且是无序的
3.通过vuex 或者localStorage 保存数据,进行数据传递
4.多级组件嵌套需要传递数据时, Vue2.4 版本提供了另一种方法----$attrs/$listeners
5. provide/inject,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。
provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
需要注意的是:**provide 和 inject 绑定并不是可响应的**。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的----vue 官方文档
所以,上面 A.vue 的 name 如果改变了,B.vue 的 this.name 是不会改变的,为了解决这种问题,可以把祖先组件的this实例传递provide过去,然后子组件通过this 获取需要的参数。耦合度太高
组件通信常见使用场景可以分为三类:
**父子通信:**
父向子传递数据是通过 props,子向父是通过 events($emit);
通过父链 / 子链也可以通信($parent / $children);ref 也可以访问组件实例;
provide / inject API;$attrs/$listeners
** 兄弟通信:**
Bus;Vuex;localStorage
**跨级通信:**
Bus;Vuex;localStorage;provide / inject API;$attrs/$listeners
vue 自定义指令
自定义指令
Vue 内置了一些非常有用的指令(比如v-html 和 v-once等),每个指令都有自身的用途
Vue 也允许注册自定义指令。它的作用价值在于当开发人员在某些场景下需要对普通 DOM 元素进行操作。
Vue 自定义指令有全局注册和局部注册两种方式。先来看看注册全局指令的方式,
通过 Vue.directive( id, [definition] ) 方式注册全局指令。然后在入口文件中进行 Vue.use() 调用。
当页面加载时,该元素将获得焦点 (注意:autofocus 在移动版 Safari 上不工作)。事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。现在让我们用指令来实现这个功能:
注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
如果想注册局部指令,组件中也接受一个 directives 的选项:
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
然后你可以在模板中任何元素上使用新的 v-focus property,如下:<input v-focus>
vue常用内置指令
v-model
v-for
v-text
v-html
v-on
v-bind
v-if/v-else
v-show
1.vuex是什么?怎么使用?哪种功能场景使用它
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。简单来说就是:应用遇到多个组件共享状态时,使用vuex。
场景:多个组件共享数据或者是跨组件传递数据时
vuex的流程
页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation,mutation会修改state中对应的值。最后通过getter把对应值跑出去,在页面的计算属性中,通过,mapGetter来动态获取state中的值
在vue组件中可以直接通过this.$store 来操作
vuex有哪几种属性
有五种,分别是State , Getter , Mutation , Action , Module (就是mapAction)
- state:vuex的基本数据,用来存储变量
- geeter:从基本数据(state)派生的数据,相当于state的计算属性,对state数据进行封装转换之后再输出
- mutation:提交更新数据的方法,必须是同步的(如果需要异步使用action)。每个mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。
- action:和mutation的功能大致相同,不同之处在于 ==》1. Action 提交的是 mutation,而不是直接变更状态。 2. Action 可以包含任意异步操作。
- modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
- actions与mutations作用类似,都是可以对状态进行修改。不同的是actions是异步操作的。actions是可以调用Mutations里的方法的。
dispatch:异步操作,写法: this.store.commit('mutations方法名',值)
Vuex中actions和mutations的区别
Mutation 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
Action Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。 .
什么是mvvm模式,谈谈你的理解?
MVVM - Model View ViewModel,数据,视图,视图模型
view 可以通过 事件绑定 的方式影响 model
model 可以通过 数据绑定 的形式影响到view,
viewModel是把 model 和 view 连起来的桥梁,这样就实现了数据的双向绑定。
请谈谈你对vue.js 生命周期的理解?
1.什么是vue.js的生命周期:Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
2.各个生命周期的作用
为什么vue中组件里面的data是一个函数而不是一个对象呢?
因为组件可能被用来创建多个实例,如果data仍然是一个纯粹的对象,则所有的实例将共享引用一个数据对象,通过提供data函数,每次创建一个新的实例之后,我们能够调用data函数从而返回一个全新的副本数据对象,这样每一个实例都有自己私有的数据空间不会互相影响
vue事件修饰符以及各个的作用?
.stop:阻止事件冒泡
.native:绑定原生事件
.once:事件只执行一次
.self 将事件绑定在自身身上,相当于阻止事件冒泡
.prevent:阻止默认事件
.passive: 2.3.0 新增,滚动事件的默认行为 (即滚动行为) 将会立即触发,不能和.prevent 一起使用
vue如何优化页面加载?
1.UI组件库尽量使用cdn的方式引入,或者下载本地通过js文件引入;
2.配置路由懒加载的方式;
3.增加loading图,提升用户体验
父组件和子组件生命周期执行的顺序?
1.加载渲染过程:
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate
-> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
2.子组件更新过程:
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
3.父组件更新过程:
父 beforeUpdate -> 父 updated
4.销毁过程:
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
获取dom节点的方式
案例解析
DOM 是一个树形结构,操作一个DOM节点,实际上就是这几个操作:更新、删除、添加、遍历
在操作DOM节点之前,需要通过各种方式先拿到这个DOM节点,常用的方法有:
一、通过元素类型的方法来操作:
- document.getElementById();//id名,在实际开发中较少使用,选择器中多用class id一般只用在顶级层存在 不能太过依赖id
- document.getElementsByTagName();//标签名
- document.getElementsByClassName();//类名
- document.getElementsByName();//name属性值,一般不用
- document.querySelector();//css选择符模式,返回与该模式匹配的第一个元素,结果为一个元素;如果没找到匹配的元素,则返回null
- document.querySelectorAll()//css选择符模式,返回与该模式匹配的所有元素,结果为一个类数组
二、根据关系树来选择(遍历节点树):
【先简单介绍一下节点:
DOM(文档对象模型)可以将任何HTML、XML文档描绘成一个多层次的节点树。所有的页面都表现为以一个特定节点为根节点的树形结构。html文档中根节点为document节点。
所有节点都有nodeType属性,代表节点的不同类型,通过nodeType属性可以来判断节点的类型。经常使用的节点主要有以下几种类型:
Element类型(元素节点):nodeType值为 1
Text类型(文本节点):nodeType值为 3
Comment类型(注释节点):nodeType值为 8
Document类型(document节点):nodeType值为 9;其规定的一些常用的属性有
document.body document.head 分别为HTML中的 <body><head>
document.documentElement为<html>标签
所有的节点都有 hasChildNodes()方法 判断有无子节点 有一个或多个子节点时返回true】
通过一些属性可以来遍历节点树:
parentNode//获取所选节点的父节点,最顶层的节点为#document
childNodes //获取所选节点的子节点们
firstChild //获取所选节点的第一个子节点
lastChild //获取所选节点的最后一个子节点
nextSibling //获取所选节点的后一个兄弟节点 列表中最后一个节点的nextSibling属性值为null
previousSibling //获取所选节点的前一兄弟节点 列表中第一个节点的previousSibling属性值为null
由于文档中的节点类型较多,遍历子节点的结果很多时候并不能得到我们想要的结果,使用遍历元素节点则很方便
三、基于元素节点树的遍历(遍历元素节点树):
parentElement //返回当前元素的父元素节点(IE9以下不兼容)
children // 返回当前元素的元素子节点
firstElementChild //返回的是第一个元素子节点(IE9以下不兼容)
lastElementChild //返回的是最后一个元素子节点(IE9以下不兼容)
nextElementSibling //返回的是后一个兄弟元素节点(IE9以下不兼容)
previousElementSibling //返回的是前一个兄弟元素节点(IE9以下不兼容)
vue获取dom节点
在vue项目中,获取dom节点可以用ref属性,这个属性就是来获取dom对象的。
<template>
<div class="contaier" ref="box" style="width: 100px;height: 100px;">
这里用来测试元素的ref属性
</div>
<button type="button" @click="showData()">点击</button>
</template>
<script>
export default {
methods: {
showData() {
console.log(this.$refs.box);
console.log(this.$refs.box.style);
}
}
}
</script>