Vue
vue的computed属性和methods区别
- computed是响应式的,methods并非响应式。
- 调用方式不一样,computed定义的成员像属性一样访问,methods定义的成员必须以函数形式调用。
- computed是带缓存的,只有其引用的响应式属性发生改变时才会重新计算,而methods里的函数在每次调用时都要执行。
- computed中的成员可以只定义一个函数作为只读属性,也可以定义get/set变成可读写属性,这点是methods中的成员做不到的
Vue 的双向绑定是如何实现的?如何追踪变化?
把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue响应式原理
父子通信
组件关系可分为父子组件通信、兄弟组件通信(new Vue() 作为 eventBus)、跨级组件通信。
父子组件通信的方法为:子组件通过props方法接受父组件的data数据,子组件通过$emit触发父组件的自定义事件,如:1
2
3
4
5
6
7
8
9
10
11
12// 父组件将数据(currentUser)和方法(logout)传递出去
<template>
  <Todo v-else ="logout" :currentUser="currentUser"/>
</template>
// 子组件接收数据和方法
props : ['currentUser'],
methods: {
  logout() {   //注册 _user
    this.$emit("logout")
  }
}
on和emit的事件必须是在一个公共的实例上,才能触发
子组件用$emit()触发事件this.$emit(‘logout’)
父组件用$on()监昕子组件的事件@logout =“logout”
父子通信
v-show和v-if指令的共同点和不同点
v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
生命周期
生命周期,即Vue 实例从创建到销毁的过程,一共分为8个阶段。生命周期可以让我们在控制整个Vue实例时形成好的逻辑。第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子。DOM 在 mounted时渲染完成。Vue生命周期举例API — Vue.js
创建前/后:
beforeCreated阶段,vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。这个时候可以加loading事件。
created阶段,vue实例的数据对象data有了,$el还没有。这个时候可以结束loading事件,也可以调用异步请求。
载入前/后:
beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。
mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:
当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:
beforeDestroy时可以做一个确认停止事件的确认框。执行 destroy 方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
css在Vue.cli中怎么安装使用?
Scss:
可以用变量,例如($变量名称=值)
可以用混合器,例如()
可以嵌套
Vue.cli中安装使用:1
2
3
4
5//安装
npm i -D sass-loader
npm i -D node-sass
//页面引用
<style lang="scss">
什么是MVVM
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作是自动的,无需人为操作DOM。
MVVM主要解决了MVC中大量的DOM 操作使页面渲染性能降低,加载速度变慢的缺陷
一些报错及解决方法
- Vue空格等报错解决方法 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- //注释掉webpack.base.config.js文件中的如下代码 
 const createLintingRule = () => ({
 /*test: /\.(js|vue)$/,
 loader: 'eslint-loader',
 enforce: 'pre',
 include: [resolve('src'), resolve('test')],
 options: {
 formatter: require('eslint-friendly-formatter'),
 emitWarning: !config.dev.showEslintErrorsInOverlay
 }*/
 })
- Vue去掉警告 You are running Vue in development mode 
 在js中加一句:- Vue.config.productionTip=false
使用Vue时的注意事项及一些小技巧
- vue实例挂载点,不能是div和html
- 单vue组件,template必需且只能有一个根结点
- 监听一个vue组件的input时加.native`@keyup.enter.native=”addTodo”`
- 使文本框自动获取焦点的方法: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- // html文件 
 <input ref="input">
 // js文件
 new Vue({
 ...
 mounted() {
 this.$refs['input'].focus()
 // this.$refs['input'].value = ''
 },
 ...
 })
- 让CSS只在当前组件中起作用,可以将当前组件的 - <style>修改为- <style scoped>
- 渲染时莫名其妙报错可以用:key="xxx.id"解决。原因:key的值是需要是唯一识别的
- 避免v-if和v-for用在一起。为什么?因为v-for 比 v-if 具有更高的优先级,通过v-if 移动到容器元素,不会再重复遍历列表中的每个值。只检查它一次,且不会在 v-if 为否的时候运算 v-for。
图片资源懒加载
| 1 | // 下载 | 
性能优化
- 频繁切换条件场景用v-show,不频繁的切换使用v-if。(v-show元素一直被渲染;v-if条件为真时才渲染)
- 依赖的属性值进行数值计算时使用computed,监听数据变化后执行异步或开销较大的操作时使用watch
- v-for比- v-if优先级高,如使用在同一个标签,会意味着每个循环都会执行- v-if,如果不是每个循环都需要判断,最好将- v-if放在循环外面
- 如果内容不需要改动,可将数据Object.freeze(data)冻结起来,防止Vue通过Object.defineProperty对数据进行劫持
- 由于在Vue组件内使用addEventListene等方式是不会自动销毁的,所以需要在组件销毁时手动removeEventListener移除这些事件的监听,以免造成内存泄露
- 图片路由资源懒加载
- 第三方插件按需引入,可借用babel-plugin-component插件
- 服务端渲染SSR,直接在服务端完成渲染,所以可以被搜索引擎爬取工具抓取(和异步获取的SPA页面相比有更好的SEO,搜索引擎爬取工具抓取不到异步返回的内容),且无需等待所有js加载完再去渲染,能加快首屏加载速度。缺点:需要Node.js环境、只支持beforCreate和created两个钩子函数、服务器负载
Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化,并没有任何永久存储的功能。每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。
十分钟入门Vuex
如何在 Vue 组件中展示状态?
一个store实例:1
2
3
4
5
6
7
8
9import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
const store = new Vuex.Store({
  state,   
  getters,    
  mutations, 
  actions, 
})
在Vue的实例中,把 store 对象提供给 “store” 选项即store:store,这可以把 store 的实例注入所有的子组件,子组件能通过this.$store访问到,如:1
2
3
4const app = new Vue({
  el: '#app',
  store,
})
Vuex的几种属性介绍
vuex一共有5种属性,分别是State、 Getter、Mutation 、Action、 Module
State
- Vuex就是一个仓库,仓库里面放了很多对象,state是唯一的数据源,相当于VUE中的data
- State里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新
- 通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
- 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
- mapState辅助函数
Getter
- Getters 可以对State进行计算操作,相当于VUE中的computed,getters 可以在多组件之间复用,如果一个状态只在一个组件内使用,是可以不用getters
- 可以通过属性访问,如 - 1 
 2
 3
 4
 5- computed: { 
 doneTodosCount () {
 return this.$store.getters.doneTodosCount
 }
 }
- 可以通过方法访问(让 getter 返回一个函数,来实现给 getter 传参,如 - store.getters.getTodoById(2)的形式),但是需要注意的是,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
- mapGetters辅助函数
Mutation
- 同步,相当于VUE中的methods,但是只能是同步。每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。它的回调函数(handler)接受state作为第一个参数,如handler(state,其他参数){}
- 不能直接调用一个 mutation handler,需要以相应的 type 调用 store.commit 方法,如: - 1 
 2
 3
 4
 5
 6
 7- mutations: { 
 increment (state, n) {
 state.count += n
 }
 }
 //调用
 store.commit('increment',额外的参数即载荷payload)
- 对象风格的提交方式,即直接使用包含 type 属性的对象 - 1 
 2
 3
 4- store.commit({ 
 type: 'increment',
 amount: 10
 })
- 在对象上添加新属性 - Vue.set(obj, 'newProp', 123)- state.obj = { ...state.obj, newProp: 123 }
Action
异步,但是actions不能对数据,只能用commit调用mutations。参数是store,可以用{commit},然后commit(‘mutations中的方法’, 参数),  this.$store.dispatch用于分发action
Module
在其他地方用引入1
2
3
4
5
6
7
8
9
10
11
12//在其他地方用引入
import {mapState,mapGetters,mapMuations, mapAtions} from 'vuex'
export default {
  computed:{
    ...mapState(['increment'])//相当于将 `this.increment()` 映射为 `this.$store.commit('increment')`
    ...mapGetters([''])
  }
  methods:{
    ...mapMuations([''])
    ...mapAtions([''])
  }
}
3 热重载Hot Reload
把getters统一为数据的获取出口,actions统一为数据的操作入口
热重载:主要在开发环境中使用;当模块内容修改时,保留Vuex数据,重载修改模块的业务逻辑;如果不用热重载,修改模块时整体刷新,数据不再保留1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37//Vuex 支持在开发过程中热重载 mutation、module、action 和 getter、
//对于 mutation 和模块,需要使用 store.hotUpdate() 方法
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations.js'
import getters from './getters.js'
import actions from './actions.js'
import modulesA from './modules/a'
Vue.use(Vuex)
const state = { ... }
const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules: {
      a: moduleA
  }
}
})
//热重载
if (module.hot) {
  // 使 action 和 mutation 成为可热重载模块
  module.hot.accept(['./getters.js','./mutations.js', './actions.js','./modules/a'], () => {
    // 获取更新后的模块
    // 因为 babel 6 的模块编译格式问题,这里需要加上 `.default`
    // 加载新模块
    store.hotUpdate({
      getters: require('./getters.js').default
      mutations: require('./mutations.js').default
      actions: equire('./actions.js').default
      modules: {
        a: require('./modules/a').default
      }
    })
  })
}
Vue-router
vue-router入门学习文章
路由执行过程:用户点击 router-link 标签时,寻找 to 属性,to 属性和 js 中配置的路径{ path: '/home', component: Home}  path 对应,找到匹配的组件,最后把组件渲染到 router-view 标签,OK。
1 $router和$route的区别是什么?都在什么时候用?
this.$router:
表示全局路由器对象,项目中通过router路由参数注入路由之后,在任何一个页面都可以通过此方法获取到路由器对象,并调用其push(), go()等方法;
this.$route:
表示当前正在用于跳转的路由器对象,可以调用其name、path、query、params等方法;1
2
3
4
5
6
7
8
9
10
11
12
13//两条路由
const routes = [
  { path: '/home', component: Home },
  { path: '/about', component: About }
]
//创建路由实例
const router = new VueRouter({
      routes,
})
//配置完成后把路由实例注入到vue根实例
const app = new Vue({
  router
})