MVVM是Model-View-ViewModel的简写,它本质上就是MVC的改进版。MVVM就是将View的状态和行为抽象化,将视图UI和业务逻辑分开,View和Model之间并没有直接的联系,而是通过ViewModel进行交互,它们之间的交互是双向的。
以下是Vue技术栈中一个双向绑定的典型例子:
{{message}}
示例中当修改input标签中的内容时,p标签的内容也会同步修改。
Vue生命周期:
名称 | 描述 |
---|---|
beforeCreate | 实例刚被创建,vue所有属性都还不存在 |
created | 实例创建完成,但$el还不存在 |
beforeMount | 挂载之前 |
mounted | 挂载之后,即data中的数值已经被渲染到元素中 |
beforeUpdate | 更新之前 |
updated | 更新之后 |
activated | |
deactivated | |
beforeDestroy | 实例被销毁前 |
destroyed | 实例被销毁后 |
示例:https://blog.csdn.net/zeping891103/article/details/78135698
双向绑定的原理是利用Object.defineProperty()进行数据劫持,然后采用结合发布者-订阅者模式监听数据的变化。当把一个 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。如第一题中的双向绑定的示例代码,它的数据劫持方式为:
var data = { message: 'HelloWorld' }
Object.defineProperty(data, 'message', {
get: function () {
return data.message;
},
set: function (newValue) {
data.message = 'newValue';
// data-v-xxxxx为Vue实例在初始化时给dom元素添加的唯一属性值
// 当message数据发生变化时,通知相关v-model绑定的元素也发生变化
document.getElementByAttr('input','data-v-xxxxx','').value = newValue;
}
})
另外,当input元素被v-modal绑定时,Vue实例为该元素添加了一个input事件,当内容发生变化时,触发this.$emit('input',' ')函数发出事件告诉Vue实例 data.message发生变化了,实现数据同步。更多有关Object.defineProperty的用法可以参考本系列的基础篇(四)中有介绍。
发布者-订阅者模式的设计思想是发布者管理所有相依于它的订阅者,并且在发布者本身的状态改变时主动发出通知,订阅者接到通知后开始响应变化并刷新。
1.父组件与子组件传参
父组件传给子组件:子组件通过props方法接受参数
子组件传给父组件:$emit方法传递参数
示例:父组件向子组件mycomp传递参数message,并添加对子组件的cbmsg事件监听
{{callback_msg}}
子组件通过props属性接收父组件传入的参数,并通过触发cbmsg事件向父组件传递参数
{{message}}
2.非父子组件间的数据传递,兄弟组件传值
使用事件总线EventBus,创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。
示例:创建Bus
// vue-bus.js
const install = function(Vue) {
const Bus = new Vue({
methods: {
emit(event, ...args) {
this.$emit(event, ...args);
},
on(event, callback) {
this.$on(event, callback);
},
off(event, callback) {
this.$off(event, callback);
}
}
});
Vue.prototype.$bus = Bus;
}
export default install;
// Vue首次创建实例时一次性引入
import VueBus from '@/assets/js/vue-bus';
Vue.use(VueBus);
new Vue({
el: '#app',
...
})
// 组件间使用
this.$bus.on('eventName',function(value){})
this.$bus.emit('eventName', value)
使用Vuex,父组件与子组件共享相同的状态值,配合...mapGetters实现数据同步更新,这时会触发变化组件的updated钩子函数,但并不会重新挂载。这里要加个题外话,在Vuex中状态是存储在一个共享对象里的,所以当有相同getters的时候将会报错,针对这种情况,可以使用命名空间namespaced: true,添加这个属性后,无论是存值、取值还是执行函数都需要加上前缀命名空间,详细可参考:https://blog.csdn.net/weixin_39015132/article/details/84143962。
hash模式:在浏览器显示的URL中带有符号“#”,#以及#后面的字符称之为hash,通过hashChange事件来监听URL的改变,用window.location.hash读取。
特点:hash虽然在URL中,但不被包括在HTTP请求中,因此hash不会重加载页面。hash内容是用来指导浏览器动作,对服务端安全无用。
history模式:在浏览器显示的URL中以“ / ”分割,没有#。这种模式采用HTML5的新特性且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
特点:前端的 URL 必须和实际向后端发起请求的 URL 一致,如http://www.xxx.com/items/id,后端如果缺少对 /items/id 的路由处理,将返回 404 错误。解决办法:当访问不到页面时,重定向到index.html页面,即app依赖的页面。
主要有两个:beforeEach,afterEach。用于对路由导航跳转前、后的监听,如跳转前检查是否包括有效Token,没有则返回登录页面。
beforeEach有3个参数to,from,next:
示例:
// Router跳转页面时,验证token
export const SetRouterTransition = function(router, store) {
/* router before */
router.beforeEach((to, from, next) => {
// check this router need auth
if(to.meta.requireAuth) {
if(store.state.app.token || getLocalStorage('api_token')) {
next();
} else {
alert('没有找到模拟TOKEN值')
next({
path: '/',
query: {
redirect: to.fullPath
}
})
}
} else {
next();
}
});
/* router after */
router.afterEach((transition) => {
let title = transition.name;
document.title = title;
});
}
// 在入口文件添加参数router和store
SetRouterTransition(router, store);
Vuex是一种用来实现状态管理的机制,它的应用核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex主要有四个模块组成:
自定义指令使用Vue.directive来定义,简单而言,就是从指令赋值中获取对添加该指令元素的操作说明,通过对操作的解析后按要求初始化该元素。
定义指令有5个钩子函数:
这些钩子函数具有相同的回调参数:
全局指令:
Vue.directive('mydir', {
inserted(el) {
console.log(el);
}
})
局部指令:
var app = new Vue({
el: '#app',
// 创建指令(可以多个)
directives: {
// 指令名称
mydir: {
inserted(el) {
console.log(el);
}
}
}
})
示例:
{{msg}}
指令内容更新前:
指令内容更新后:
通过vue实例的 filters 属性或 Vue.filter() 函数创建过滤器,在值运算中用竖杠 | 表示过滤:
{{ msg | capitalize }}
局部过滤器:
var vm=new Vue({
el:"#app",
data:{
msg:''
},
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
全局过滤器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。
该组件也常用于路由导航是否缓存页面内容:
这时,在进入导航页面时将不会重新渲染页面,如果需要更新页面数据可以在生命周期钩子函数 activated 里操作。
事件修饰符是指与事件触发相关的修饰符。如要阻止冒泡事件需要用到event.stopPropagation(),然而使用事件修饰符,仅需@click.stop即可。
事件修饰符有以下几种,以click事件为例:
修饰符间可以串联使用,如用 @click.stop.once,表示阻止冒泡并仅执行一次。
按键修饰符是指与键盘事件相关的修饰符。如对Enter键的监听@keyup.enter,快捷组合件的监听等。按键修饰符一般与input标签配合使用,有以下几种:
vue2.x版本后新增了下面几种修饰符:
Methods里的函数每次调用都会从头开始执行一遍;computed里的函数只要入参相同,只在首次执行计算过程,其它的会从缓存中直接返回已经计算过的值,不会重新计算。