对于MVVM的理解
由 Model、View、ViewModel 三部分构成,由MVC衍生。
Model: 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑,
View: 代表UI 组件,它负责将数据模型转化成UI 展现出来,
ViewModel: 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。 (注意)
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
Vue.js双向数据原理
Vue.js 可以说是MVVM 架构的最佳实践,专注于 MVVM 中的 ViewModel,不仅做到了数据双向绑定,而且也是一款相对来比较轻量级的JS 库,API 简洁,很容易上手。
Vue.js 是采用 Object.defineProperty 的 getter 和 setter,并结合观察者模式来实现数据绑定的。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。(注意:据悉vue3.0将采用Proxy替代Object.defineProperty)
图的解析:
Observer :数据监听器,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者,内部采用Object.defineProperty的getter和setter来实现 。
Compile :指令解析器,它的作用对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数 。
Watcher :订阅者,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数 。
Dep :消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify 函数,再调用订阅者的 update 方法 。
执行过程:
当执行 new Vue() 时,Vue 就进入了初始化阶段,一方面Vue 会遍历 data 选项中的属性,并用 Object.defineProperty 将它们转为 getter/setter,实现数据变化监听功能;另一方面,Vue 的指令编译器Compile 对元素节点的指令进行扫描和解析,初始化视图,并订阅 Watcher 来更新视图, 此时Wather 会将自己添加到消息订阅器中(Dep),初始化完毕。
当数据发生变化时,Observer 中的 getter 方法被触发(注意这里触发什么),getter 会立即调用Dep.notify(),Dep 开始遍历所有的订阅者,并调用订阅者的 update 方法,订阅者收到通知后对视图进行相应的更新。同理当表单输入内容发生变化时, 就会触发setter,watcher监听机制就会执行, watcher通知Vue生成新的VDOM树,再通过render函数进行渲染,生成真实DOM 。
通过 Object.defineProperty 实现见简单的双向数据绑定:
<body>
<div id="demo"></div>
<input type="text" id="inp">
</body>
<script>
let obj = {};
let demo = document.querySelector('#demo');
let inp = document.querySelector('#inp');
Object.defineProperty(obj,'name',{
get : () => {
return inp.value;
},
set : (newVal) => {//当该属性被赋值的时候触发
inp.value = newVal;
demo.innerHTML = newVal;
}
});
inp.addEventListener('input',(e) => {
// 给obj的name属性赋值,进而触发该属性的set方法
obj.name = e.target.value;
})
obj.name = 'huqinggui';//在给obj设置name属性的时候,触发了set这个方法
</script>
为什么vue3.0要用Proxy替代Object.defineProperty 实现双向数据绑定(待补充完善)
替换不是因为不好,是因为有更好的方法使用效率更高
那么到底为什么要用Proxy呢?既然想要替代了,说明一个有缺点,一个有优点的那么我们就来分析下他们的优缺点:
Object.defineProperty 的缺点:
总体上说致命的缺点是:
- 不能监听数组的变化
- 必须遍历对象的每个属性
- 必须深层遍历嵌套的对象
细分就是以下几点:
1.对IE11的兼容性(现在除了特殊的需求,基本上对IE都不考虑了)
2. 无法检测数组的变化
Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。 而且使用这些方法(push, pop, shift, unshift,splice, sort, reverse
…)是不能触发set的,Vue中能监听是因为对这些方法进行了重写
var a = {},
bValue = 1;
Object.defineProperty(a,"b",{
set: function(value){
bValue = value;
console.log("setted");
},
get: function(){
return bValue;
}
});
a.b = []; //setted
a.b = [1,2,3]; //setted
a.b[1] = 10; //无输出
a.b.push(4); //无输出
a.b.length = 5; //无输出
当a.b被设置为数组后,只要不是重新赋值一个新的数组对象,任何对数组内部的修改都不会触发setter方法的执行。所以要想实现实现数组的双向绑定,则必须通过Arr = newArr;这样的语句实现。同样常见的数组方法也不会触发,在框架中对这些方法进行了重写才能实现效果。
3.只能监听属性,而不是监听对象本身,需要对对象的每个属性进行遍历
对于原本不在对象中的属性难以监听。在Vue 2.x里,是通过 “callback + 遍历 data 对象” 来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择,而Proxy就显示了这方面的优势
4.当对象增删的时候,是监控不到的
比如:data = {a:"a"},这个时候如果我们设置data.test = "test",这个时候是监控不到的。因为在observe data的时候,会遍历已有的每个属性(比如a),添加getter/setter,而后面设置的test属性并没有机会设置getter/setter,所以检测不到变化。同样的,删除对象属性的时候,getter/setter会跟着属性一起被删除掉,拦截不到变化。
ES6中的Proxy的优点:
总的来说呢,Proxy是刚好解决了上述 Object.defineProperty 的缺点:
针对对象:针对整个对象,而不是对象的某个属性,所以也就不需要对 keys 进行遍历。
支持数组:Proxy 不需要对数组的方法进行重载,省去了众多 hack,减少代码量等于减少了维护成本,而且标准的就是最好的。
当然除此之外还有以下几个原因:
Proxy 的第二个参数可以有 13 种拦截方法,这比起 Object.defineProperty() 要更加丰富
Proxy 作为新标准受到浏览器厂商的重点关注和性能优化,相比之下 Object.defineProperty() 是一个已有的老方法。
请详细说下你对vue生命周期的理解
vue生命周期总共分为8个阶段: 创建前/后,载入前/后,更新前/后, 销毁前/后
beforeCreate (创建前)vue实例的挂载元素$el
和数据对象 data
都是undefined
, 还未初始化
created (创建后) 完成了 data
数据初始化, el
还未初始化
beforeMount (载入前) vue实例的$el
和data
都初始化了, 相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
mounted (载入后) 在el
被新创建的 vm.$el
替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html
内容替换el
属性指向的DOM
对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互
beforeUpdate (更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated (更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
beforeDestroy (销毁前) 在实例销毁之前调用。实例仍然完全可用。
destroyed (销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
vue中 key
值的作用 (v-for)
key 的特殊属性主要用在 Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。(有效的避免就地复用)
有相同父元素的子元素必须有独特的key。重复的key会造成渲染错误。
最常见的用例是结合 v-for:
<ul>
<li v-for="item in items" :key="item.id">...</li>
</ul>
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
完整地触发组件的生命周期钩子
触发过渡
<transition>
<span :key="text">{{ text }}</span>
</transition>
当 text 发生改变时,<span> 会随时被更新,因此会触发过渡。
vue中子组件调用父组件的方法
子组件调用父组件的方法可以使用this.$emit()
v-show
和v-if
指令的共同点和不同点?
v-show
指令是通过修改元素的display
CSS属性让其显示或者隐藏。
v-if
指令是直接销毁和重建DOM达到让元素显示和隐藏的效果(注意:v-if 可以实现组件的重新渲染),因此我们要尽量减少v-if的使用,因为它消耗性能。
如何让CSS只在当前组件中起作用?
将当前组件的<style>
修改为<style scoped>
,关键点在scoped,代表作用域,限制css的作用在当前组件。的作用是什么?
<keep-alive></keep-alive>的作用是什么?
<keep-alive></keep-alive>
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
大白话: 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>
进行缓存,
这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染 。
Vue中引入组件的步骤?
引入:
1.采用ES6的import ... from ...
语法
2.CommonJS的require()
方法引入组件
注册:
Vue.component('my-component',
{ template: '<div>A custom component!</div>'})
3.使用组件<my-component></my-component>
指令v-el的作用是什么?和v-ref有什么区别?
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标.可以是 CSS 选择器,也可以是一个 HTMLElement 实例
通过v-el
我们可以获取到DOM
对象
通过v-ref
获取到整个组件(component
)的对象
<template id="demo">
<h2>组件对象</h2>
</template>
<div id="app">
<h2 v-el:myh2>DOM对象</h2>
<button @click="getDom">获取DOM对象</button>
<hr>
<demo v-ref:mycom></demo>
<button @click="getCom">获取组件对象</button>
</div>
<script src="../../../js/vue/vue/1.0/vue.js"></script>
<script type="application/javascript">
//创建Vue对象
new Vue({
el:'#app'
,methods:{
getDom(){
console.log(this.$els.myh2);
}
,getCom(){
console.log(this.$refs.mycom);
}
}
,components:{
'demo':{
template:'#demo'
}
}
});
</script>
在Vue中使用插件的步骤
1. 采用ES6的import ... from ...
语法
2. 使用全局方法Vue.use( plugin )
使用插件,可以传入一个选项对象 ,需要
Vue.use(MyPlugin, { someOption: true })
请列举出3个Vue中常用的生命周期钩子函数?
1.created: 实例已经创建完成之后调用,在这一步,实例已经完成数据观测, 属性和方法的运算, watch/event事件回调. 然而, 挂载阶段还没有开始, $el
属性目前还不可见
2. mounted: el
被新创建的 vm.$el
替换,并挂载到实例上去之后调用该钩子。如果 root
实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el
也在文档内
3. activated::keep-alive
组件激活时调用
请简述下Vuex的原理和使用方法
数据单向流动
一个应用可以看作是由上面三部分组成: View, Actions,State,数据的流动也是从View => Actions => State =>View 以此达到数据的单向流动.
但是项目较大的, 组件嵌套过多的时候, 多组件共享同一个State会在数据传递时出现很多问题.Vuex就是为了解决这些问题而产生的.
Vuex可以被看作项目中所有组件的数据中心,我们将所有组件中共享的State抽离出来,任何组件都可以访问和操作我们的数据中心
Vuex的组成:一个实例化的Vuex.Store由state, mutations和actions三个属性组成:
1.state中保存着共有数据
2.改变state中的数据有且只有通过mutations中的方法,且mutations中的方法必须是同步的
3.如果要写异步的方法,需要些在actions中, 并通过commit到mutations中进行state中数据的更改.
vue watch的高级用法--监听对象的属性变化
1.监听对象需要深度监听 ,如下代码可以监听整个msg对象的变化
watch: {
msg: {
handler(newValue, oldValue) {
console.log(newValue)
},
deep: true
}
}
2. 监听对象里面某个属性的变化,通过computed做中间层实现
computed: {
channel() {
return this.msg.channel
}
},
watch:{
channel(newValue, oldValue) {
console.log('new: %s, old: %s', newval, oldVal)
//这里面可以执行一旦监听的值发生变化你想做的操作
}
}
vue等单页面应用及其优缺点
优点:
1、具有桌面应用的即时性、网站的可移植性和可访问性。
2、用户体验好、快,内容的改变不需要重新加载整个页面。
3、基于上面一点,SPA相对对服务器压力小。
4、良好的前后端分离。SPA和RESTful架构一起使用,后端不再负责模板渲染、输出页面工作,web前端和各种移动终端地位对等,后端API通用化。
5、同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端;
缺点:
1、不利于SEO。(如果你看中SEO,那就不应该在页面上使用JavaScript,你应该使用网站而不是Web应用,或者通过ssr渲染)
2、初次加载耗时相对增多。
3、导航不可用,如果一定要导航需要自行实现前进、后退。
vue prop不同数据类型设置默认值
vue prop 会接收不同的数据类型,这里列出了 常用的数据类型的设置默认值的写法,其中包含: Number, String, Boolean, Array, Function, Object
refAge: {
type: Number,
default: 0
},
refName: {
type: String,
default: ''
},
hotDataLoading: {
type: Boolean,
default: false
},
hotData: {
type: Array,
default: () => {
return []
}
},
getParams: {
type: Function,
default: () => () => {}
},
meta: {
type: Object,
default: () => ({})
}
Vue实现组件props双向绑定解决方案
注意: 子组件不能直接修改prop过来的数据,会报错
方案一:
- 用data对象中创建一个props属性的副本
- watch props属性 赋予data副本 来同步组件外对props的修改
- watch data副本,emit一个函数 通知到组件外
子组件:
<template>
<div class="hello">
<h1 v-show="visible">测试显示隐藏</h1>
<div @click="cancel">点我点我</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
value: {
type: Boolean,
default:false
}
},
data () {
return {
visible: false
}
},
watch:{
value(val) {
this.visible = val;
},
// 只有这一步 才触发父组件的方法 由父组件的 paretnVisibleChange 方法去改变父
组件的数据
visible(val) { this.$emit("paretnVisibleChange",val); } },
// 子组件修改的只能是子组件 本身的data数据
methods:{
cancel(){
this.visible = !this.visible;
}
},
// 注意这段代码 为了同步父组件的数据
mounted() {
if (this.value) {
this.visible = true;
}
}
}
</script>
<style scoped>
</style>
父组件:
<template>
<div id="app">
<HelloWorld :value = 'visible' @paretnVisibleChange="visibleChange" />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
export default {
name: 'App',
components: {
HelloWorld
},
data () {
return {
visible: true
}
},
methods:{
// 父子组件就是靠的这个方法改变数据的
visibleChange(val){
this.visible = val;
}
}
}
</script>
方案一 的缺点就是 父组件必须有个 visibleChange 这样的方法,有点累赘。
这时候 想到了 v-model
因为
<input v-model = 'someThing'>
是下面这段代码的语法糖
<input :value = 'someThing' @input = 'someThing = $event.target.value'>
也就是说 v-mode 自带了 一个改变父组件的方法 类似方案一的 paretnVisibleChange
但是使用 v-model 的时候 需要注意两点:
1.子组件要接受 value 属性
2.value改变时 要触发input 事件
方案二:
子组件:
<template>
<div class="hello">
<h1 v-show="visible">测试显示隐藏</h1>
<div @click="cancel">点我点我</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
value: {
type: Boolean,
default:true
}
},
data () {
return {
visible: false
}
},
watch:{
value(val) {
this.visible = val;
},
// 子组件 改变的就是这段代码
visible(val) {
this.$emit("input",val);
}
},
methods:{
cancel(){
this.visible = !this.visible;
}
},
mounted() {
if (this.value) {
this.visible = true;
}
}
}
</script>
父组件代码如下:(父组件省去了 paretnVisibleChange 方法)
<template>
<div id="app">
<HelloWorld v-mode = 'visible'/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
export default {
name: 'App',
components: {
HelloWorld
},
data () {
return {
visible: true
}
}
}
</script>
方案三:
vue 2.3.0之后新增了 .sync 属性 使用方法跟 v-model 类似 具体 请参考 : https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-修饰符
下面我写了一个简单的sync 的使用实例:
父组件的代码如下:
<li
is="DragCompent"
v-for="(item, index) in layoutItem"
:item="item"
v-model="cloneLeftItemText"
:leftDragItemIsDraged.sync = 'leftDragItemIsDraged'
:key="index">
</li>
子组件的代码如下:
props: {
leftDragItemIsDraged: {
type: Boolean,
default: false
}
},
watch:{
leftDragItemIsDraged(val) {
this.thisLeftDragItemIsDraged = val;
},
thisLeftDragItemIsDraged(val){
this.$emit('update:leftDragItemIsDraged', val)
}
}
效果图:
active-class是哪个组件的属性?嵌套路由怎么定义?
vue-router模块的router-link组件。
嵌套路由请参考: https://blog.csdn.net/github_26672553/article/details/54861174
怎么定义vue-router的动态路由?怎么获取传过来的动态参数?
在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id 例如 : this.$route.params.id
params 和 query的区别
params代表路由参数
query代表页面跳转参数
vue-router有哪几种导航钩子?
三种,
一种是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。(常用)
第二种:组件内的钩子;
第三种:单独路由独享组件
具体参考: https://www.jianshu.com/p/aae084e97452
scss是什么?安装使用的步骤是?
预处理css,把css当成函数编写,定义变量,嵌套。 先装css-loader、node-loader、sass-loader等加载器模块,在webpack-base.config.js配置文件中加多一个拓展:extenstion,再加多一个模块:module里面test、loader(现在的vue脚手架已经集成了)
scss是什么?在vue.cli中的安装使用步骤是?有哪几大特性?
css的预编译。
使用步骤:
第一步:用npm 下三个loader(sass-loader、css-loader、node-sass)
第二步:在build目录找到webpack.base.config.js,在那个extends属性中加一个拓展.scss
第三步:还是在同一个文件,配置一个module属性
第四步:然后在组件的style标签加上lang属性 ,例如:lang=”scss”
有哪几大特性:
1、可以用变量,例如($变量名称=值);
2、可以用混合器,例如:
定义了字体的混合器
@mixin font-dpr($font-size){
$font:$font-size/2;
font-size: $font;
[data-dpr="2"] & { font-size: $font+2px;}
[data-dpr="3"] & { font-size: $font+4px;}
}
使用方法如下
.div{
@include font-dpr(24px);
}
3、可以嵌套
mint-ui是什么?怎么使用?说出至少三个组件使用方法?
基于vue的前端组件库。npm安装,然后import样式和js,vue.use(mintUi)全局引入。在单个组件局部引入:import {Toast} from ‘mint-ui’。组件一:Toast(‘登录成功’);组件二:mint-header;组件三:mint-swiper
v-model是什么?怎么使用? vue中标签怎么绑定事件?
可以实现双向绑定,在表单元素上使用,指令(v-class、v-for、v-if、v-show、v-on)。vue的model层的data属性。绑定事件:<input @click=doLog() />
axios是什么?怎么使用?描述使用它实现登录功能的流程?
请求后台资源的模块。npm install axios -S装好,然后发送的是跨域,需在配置文件中config/index.js进行设置。后台如果是Tp5则定义一个资源路由。js中使用import进来,然后.get或.post。返回在.then函数中如果成功,失败则是在.catch函数中
axios+tp5进阶中,调用axios.post(‘api/user’)是进行的什么操作?axios.put(‘api/user/8′)呢?
跨域,添加用户操作,更新操作。
什么是RESTful API?怎么使用?
是一个api的标准,无状态请求。请求的路由地址是固定的,如果是tp5则先路由配置中把资源路由配置好。标准有:.post .put .delete
vuex是什么?怎么使用?哪种功能场景使用它?
vue框架中状态管理。在main.js引入store,注入。新建了一个目录store,….. export 。场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
mvvm框架是什么?它和其它框架(jquery)的区别是什么?哪些场景适合?
一个model+view+viewModel框架,数据模型model,viewModel连接两个
区别:vue数据驱动,通过数据来显示视图层而不是节点操作
场景:数据操作比较多的场景,更加便捷。
自定义指令(v-check、v-focus)的方法有哪些?它有哪些钩子函数?还有哪些钩子函数参数?
全局定义指令:在vue对象的directive方法里面有两个参数,一个是指令名称,另外一个是函数。组件内定义指令
钩子函数:bind(绑定事件触发)、inserted(节点插入的时候触发)、update(组件内相关更新)
钩子函数参数:el、binding
说出至少4种vue当中的指令和它的用法?
v-if:判断是否隐藏;v-for:数据循环出来;v-bind:class:绑定一个属性;v-model:实现双向绑定 。
vue-router是什么?它有哪些组件?
vue用来写路由一个插件。router-link、router-view 。
导航钩子有哪些?它们有哪些参数?
导航钩子有:a/全局钩子和组件内独享的钩子。b/beforeRouteEnter、afterEnter、beforeRouterUpdate、beforeRouteLeave。
参数:有to(去的那个路由)、from(离开的路由)、next(一定要用这个函数才能去到下一个路由,如果不用就拦截)最常用就这几种。
Vue的双向数据绑定原理是什么? ( vue data是怎么实现的 )
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
详细请参考: http://www.cnblogs.com/libin-1/p/6893712.html
具体步骤:
第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter
和getter
这样的话,给这个对象的某个值赋值,就会触发setter
,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
请详细说下你对vue生命周期的理解?
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreated阶段,vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,$el还没有。
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
请说下封装 vue 组件的过程?
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性等问题。
然后,使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
你是怎么认识vuex的?
vuex可以理解为一种开发模式或框架。比如PHP有thinkphp,java有spring等。
通过状态(数据源)集中管理驱动组件的变化(好比spring的IOC容器对bean进行集中管理)。
应用级的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。
vue-loader是什么?使用它的用途有哪些?
解析.vue文件的一个加载器,跟template/js/style转换成js模块。
用途:js可以写es6、style样式可以scss或less、template可以加jade等
请说出vue.cli项目中src目录每个文件夹和文件的用法?
assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置;view视图;app.vue是一个应用主组件;main.js是入口文件
vue.cli中怎样使用自定义的组件?有遇到过哪些问题吗?
第一步:在components目录新建你的组件文件(smithButton.vue),script一定要export default
第二步:在需要用的页面(组件)中导入:import smithButton from ‘../components/smithButton.vue’
第三步:注入到vue的子组件的components属性上面,components:{smithButton}
第四步:在template视图view中使用,<smith-button> </smith-button>
问题有:smithButton命名,使用的时候则smith-button。
聊聊你对Vue.js的template编译的理解?
简而言之,就是先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点)
详情步骤:
首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。另外compile还负责合并option。
然后,AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)
Vue的路由实现:hash模式 和 history模式
hash模式:
在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取; 特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。 hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xiaogangzai.com
,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
history模式:
history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。 history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id
。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”