1.热重载:修改template异步渲染
修改JS会重新加载组件、保持组件状态统一
vue-style-loader解决style热重载,
2.scope:
<template>
<div class="example" data-v-f3f3eg9>hi</div>
</template>
<style>
.example[data-v-f3f3eg9] {
color: red;
}
</style>
3.watch 监听:
- watch主要用于监控vue实例的变化,它监控的变量当然必须在data里面声明才可以,它可以监控一个变量,也可以是一个对象
// 监听路由
watch: {
'$route':'function(){ ... }'
}
// 监听数据
new Vue({
el: '#root',
data: {
cityName: 'shanghai'
},
watch: {
cityName(newName, oldName) {
// ...
}
}
})
/* watch有一个特点,当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。
比如当父组件向子组件动态传值时,子组件props首次获取到父组件传来的默认值时,也需要执行函数,此时就需要将immediate设为true */
// 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听
new Vue({
el: '#root',
data: {
cityName: {id: 1, name: 'shanghai'}
},
watch: {
cityName: {
handler(newName, oldName) {
// ...
},
immediate: true,
deep: true
}
}
})
4.computed 计算属性:
-
computed用来监控自己定义的变量,该变量不在data里面声明,直接在computed里面定义,然后就可以在页面上进行双向数据绑定展示出结果或者用作其他处理;
-
computed比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化 ;
举例:购物车里面的商品列表和总金额之间的关系,只要商品列表里面的商品数量发生变化,或减少或增多或删除商品,总金额都应该发生变化。这里的这个总金额使用computed属性来进行计算是最好的选择
computed: { name () { return this.state.store.name } }
-
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用
mapState
辅助函数帮助我们生成计算属性// 映射 this.count 为 store.state.count computed: mapState([ 'name', 'count' ]) // mapState 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢? computed: { localComputed () { /* ... */ }, // 使用对象展开运算符将此对象混入到外部对象中 ...mapState({ // ... }) }
5.store :
-
Vue.use(Vuex)
-
store 注入进Vue根实例
const store = new Vuex.Store({ modules: { app }, getters }) new Vue({ el: '#app', router, store, render: h => h(App) })
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误
不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更
const store = new Vuex.Store({
// ...
strict: process.env.NODE_ENV !== 'production'
})
6.Router:
-
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 用创建好的实例调用
beforeRouteEnter
守卫中传给next
的回调函数。
-
路由守卫:
- 全局&路由独享:beforeEach、beforeResolve(v2.5.0+新增)、afterEach ;beforeEnter(路由独享,类似beforeEach)
- 组件内:beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave
-
定义路由:
-
Vue.use(Router)
-
定义组件
-
router = new Router({ 加入组件路由 })
-
router 注入进Vue根实例
new Vue({ el: '#app', router, store, render: h => h(App) })
-
-
this.$router
访问路由器、this.$route
访问当前路由export default { computed: { username () { return this.$route.params.username } }, methods: { goBack () { window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } }
-
动态路由传参
const router = new VueRouter({ routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] }) const User = { template: '<div>User {{ $route.params.id }}</div>' }
-
嵌套路由
const router = new VueRouter ({ routes:[ { path:'/user/:id', component:User, children:[ { path:'cat' component: Cat } ] } ] })
-
编程式路由
const router = new VueRouter({ routes: [ { path: '/user/:userId', name: 'user', component: User } ] }) const userId = '123' // 字符串 this.$router.push('/user') // /user?id=123 this.$router.push({path:'/user', query:{userId}}) // /user/123 this.$router.push({path:`/user/${userId}`}) // /user/123 this.$router.push({name:'/user', params:{userId}})
-
router.replace
跟
router.push
很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 , 替换掉当前的 history 记录 -
命名视图
<div> <h1>User Settings</h1> <router-view/> <router-view name="helper"/> </div> { path: '/settings', // 你也可以在顶级路由就配置命名视图 component: UserSettings, children: [{ path: 'emails', component: UserEmailsSubscriptions }, { path: 'profile', components: { default: UserProfile, helper: UserProfilePreview } }] }
-
路由别名
别名的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构
const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })
-
路由Props解耦
const User = { props: ['id'], template: '<div>User {{ id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true }, // 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项: { path: '/user/:id', components: { default: User, sidebar: Sidebar }, props: { default: true, sidebar: false } } ] })
-
记忆滚动条:scrollBehavior
const router = new VueRouter({ routes: [...], scrollBehavior (to, from, savedPosition) { // return 期望滚动到哪个的位置 if (savedPosition) { return savedPosition } else { return { x: 0, y: 0 } } } })
-
路由懒加载:异步组件
- 工厂函数
Vue.component( 'async-webpack-example', // 这个 `import` 函数会返回一个 `Promise` 对象。 () => import('./my-async-component') )
- 2.3.0+ 新增
const AsyncComponent = () => ({ // 需要加载的组件 (应该是一个 `Promise` 对象) component: import('./MyComponent.vue'), // 异步组件加载时使用的组件 loading: LoadingComponent, // 加载失败时使用的组件 error: ErrorComponent, // 展示加载时组件的延时时间。默认值是 200 (毫秒) delay: 200, // 如果提供了超时时间且组件加载也超时了, // 则使用加载失败时使用的组件。默认值是:`Infinity` timeout: 3000 })
7.Dom事件修饰符
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
8.vue 使用 clipboard 实现复制功能
npm install clipboard --save
9.挂载Vue全局方法:
import Vue from 'vue'
import axios from 'axios'
Vue.prototype.axios = axios
Vue.axios.post('url', { name: '' })
.then(response => {
console.log(response)
})
.catch(response => {
console.log(response)
})
.finally(() => (me.loading= false));
10.虚拟DOM:
-
虚拟DOM存在的意义:vdom 的真正意义是为了实现跨平台,服务端渲染,以及提供一个性能还算不错 Dom 更新策略
-
diff算法:会对新旧两棵树进行一个深度的遍历,每个节点都会有一个标记。每遍历到一个节点就把该节点和新的树进行对比,如果有差异就记录到一个对象中
-
平层Diff,只有以下4种情况:
1、节点类型变了,例如下图中的P变成了H3。我们将这个过程称之为REPLACE。直接将旧节点卸载并装载新节点。旧节点包括下面的子节点都将被卸载,如果新节点和旧节点仅仅是类型不同,但下面的所有子节点都一样时,这样做效率不高。但为了避免O(n^3)的时间复杂度,这样是值得的。这也提醒了开发者,应该避免无谓的节点类型的变化,例如运行时将div变成p没有意义
2、节点类型一样,仅仅属性或属性值变了。我们将这个过程称之为PROPS。此时不会触发节点卸载和装载,而是节点更新
3、文本变了,文本对也是一个Text Node,也比较简单,直接修改文字内容就行了,我们将这个过程称之为TEXT
4、移动/增加/删除 子节点,我们将这个过程称之为REORDER
-
更新真实DOM: diff结果表通过js的DOM fragment更新到浏览器DOM中
11.keep-alive :
activated、deactivated这两个生命周期钩子函数会被执行
- 例如我们将某个列表类组件内容滑动到第100条位置,那么我们在切换到一个组件后再次切换回到该组件,该组件的位置状态依旧会保持在第100条列表处
<keep-alive>
<loading></loading>
</keep-laive>
- 有的产品可能会要求在每一次进入一个组件时页面的初始位置都是保持在顶部的,这里可以利用Vue中的滚动行为,但是前提是你是HTML5 history模式
const router=new VueRouter({
routes:[
{
path:"/",
component:Home
}
],
scrollBehavior(to,form,savedPosition){
//scrollBehavior方法接收to,form路由对象
//第三个参数savedPosition当且仅当在浏览器前进后退按钮触发时才可用
//该方法会返回滚动位置的对象信息,如果返回false,或者是一个空的对象,那么不会发生滚动
//我们可以在该方法中设置返回值来指定页面的滚动位置,例如:
return {x:0,y:0}
//表示在用户切换路由时让是所有页面都返回到顶部位置
//如果返回savedPosition,那么在点击后退按钮时就会表现的像原生浏览器一样,返回的页面会滚动过到之 前按钮点击跳转的位置,大概写法如下:
if(savedPosition){
return savedPosition
}else{
return {x:0,y:0}
}
//如果想要模拟滚动到锚点的行为:
if(to.hash){
return {
selector:to.hash
}
}
}
})