Vue必懂的知识点【基础篇】

1,584 阅读9分钟

把自己的学习使用记录在本地电脑,这次整理出来分享一下。个人认为都是平时工作当中用到的比较多的。希望对你们有帮助。

基础复习

跨域配置: 域名、端口

1、跨域是浏览器之间的, 因为服务器之间是不存在跨域的,所以,配置代理之后,浏览器先发给代理服务器,然后 代理服务器去跟接口交流 就不存在跨域了。

2、 多个请求地址,就在proxy那配置 多个对象就行了。

负载均衡

其实只需要在ngix中添加一个 配置就能解决。

options的根属性

  • el:目的地(string||DOM元素)
  • template 模板
  • data是一个函数,return一个对象, 对象中的key data中的属性...在dom中直接用,在js中 this.xxx
  • components: key是组件名,value是组件对象
  • methods: 一般用来配合 xxx事件
  • props: 子组件接收的参数设置 ['title', 'name']

指令

  • v-if: (留坑:<!----> 插入\移除 ) 和 v-show: (添加样式:display:none)
  • v-else-if/v-if: 必须和v-if是相邻的元素
  • v-bind/v-on: bind是给属性赋值, v-on 绑定事件
  • v-bind:单项数据流(vue -->-html): 对象、数组、三目运算、绑定内联样式
  • v-model:双向数据流(vue --> html --> vue):
    v-model 指令在 <input> (<input> 标签有多种类型,如 button、select 等等)及 <textarea> 元素上进行双向数据绑定。但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。 区别详情

附加功能: 过滤器filter & 监视watch改动

  • 过滤器 可以给 数据显示 进行 添油加醋
<!-- 在双花括号中 -->
{{ message | filterA }}

<!-- 在 'v-bind' 中 -->
<div v-bind:id="rawId | filterA"></div>
  1. 组件的选项中定义本地的过滤器: filters: {filterA: function (value) {return value}}
  2. 创建 Vue 实例之前全局定义过滤器: Vue.filter('filterA', function (value) {return value})
  • {{ watchfn1: 'xxx' }} //监视xxx并通过watchfn1函数处理输出
  • key是属于data属性的属性名,value是监视后的行为
  • 基础类型 简单监视、复杂类型 深度 监视
  • 全局: 组件/过滤器 让大家直接用 全局不带s
  • 过滤器: function(原数据,参数1,参数2){return 结果;} 调用 {{ '原数据'| 过滤器名(参数1,参数2) }}
  • watch:单个监视
  • computed: 群体监视

slot

  • 内置的组件

vue响应式原理

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。 这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

  • 注意:属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的,因为 Vue 会在初始化实例时对属性执行 getter/setter 转化。

异步更新队列 (重灾区)

因为Vue 在更新 DOM 时是异步执行的。如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。 为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。

Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
    return {
      message: '未更新'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = '已更新'
      console.log(this.$el.textContent) // => '未更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '已更新'
      })
    }
  }
})

vue双向数据绑定原理

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

Vue实现这种数据双向绑定的效果,需要三大模块:

Observer:能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者 Compile:对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数 Watcher:作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

vue生命周期的执行过程

首先创建一个vue实例,Vue(); 在创建Vue实例的时候,执行了init(),在init过程中首先调用了beforeCreate。

  • beforeCreate:初始化了部分参数,如果有相同的参数,做了参数合并,执行beforeCreate;el和数据对象都为undefined,还未初始化;

  • created:初始化了 Inject、Provide 、props、methods、data、computed和watch,执行created ;data有了,el还没有;

  • beforeMount:检查是否存在el属性,存在的话进行渲染dom操作,执行beforeMount;$el和data都初始化了,但是dom还是虚拟节点,dom中对应的数据还没有替换;

  • mounted:实例化 Watcher,渲染dom,执行mounted;vue实例挂载完成,dom中对应的数据成功渲染;

  • beforeUpdate:在渲染dom 后,执行了mounted 钩子后,在数据更新的时候,执行 beforeUpdate;

  • updated:检查当前的watcher列表中,是否存在当前要更新数据的watcher,如果存在就执行updated;

  • beforeDestroy:检查是否已经被卸载,如果已经被卸载,就直接return出去,否则执行beforeDestroy;

  • destroyed:把所有有关自己痕迹的地方,都给删除掉;


组件传值

父传子

  1. 在调用组件的时候 绑定一个属性,此属性就可以在 子组件中获取到 <fu-component v-bind:users="users"></fu-component>
  2. 在子组件中获取并使用: props: ["users"], 这样就可以使用了:<div>User {{ users }}</div>

总结:

  • 父用子 先有子,声明子, 使用子。
  • 父传子 绑定属性, 子声明(接收), 子直接用。

子传父$emit

  • 在子组件注册 this.$emit("eventName","子向父传 值"); 再父组件上 v-on:eventName="xxx($event)".
  • 在eventName事件中就可以写逻辑代码了.

兄弟组件通信

跨多层级组件通信

  1. provide & inject 父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
  2. eventBus模式 而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。
  • 避免 this.$parent

Vue.js 支持组件嵌套,并且子组件可访问父组件的上下文。访问组件之外的上下文违反了 基于模块开发 的 第一原则 。因此你应该尽量避免使用 this.$parent 。

任意传值使用 vuex

已下有详细讲解


Vue路由

  • 首先安装路由 npm install vue-router
  • main.js 使用路由 Vue.use(VueRouter)
  • 配置路由:const router = new VueRouter({ routers: [ {path: "/", component: Home}],//配置路由地址 mode: "history" //去除# 配置(发布后刷新404的话就需要服务器配置WEB-INF) })
  • 同时在使用的地方加上 <router-view></router-view>
  • a标签会重新加载页面,所以 使用 <router-link></router-link>标签
  • jsonplaceholder.typicode.com 在线json接口

参数传递

  1. "动态路径参数"(dynamic segment)
  • 路由 参数的声明: { path: '**/user/:id**', component: User }
  • 参数的获取(使用): this.$route.params.id
  1. 捕获所有路由
  • path: '*': 会匹配所有路径
  • path: '/user-*' : 会匹配以 /user- 开头的任意路径.$route.params 内会自动添加一个名为 pathMatch 参数.
  1. query传参
  • path:'/componentsB' query:{que:'我是通过query传到组件B的参数'} 页面通过this.$route.query来获取参数

精讲路由

路由的跳转

1、第一种 router-link 声明式

  • <router-link to="name"> </router-link> tag属性 可自定义 显示标签; :to="{name:'xxx',params:{key:value}}" 这种写法就是 根据路由定义的 name来动态获取跳转路由 {{this.$route.params.username}} 获取路由参数

2、第二种 编程式

 this.$router.go(-1);   //跳转到上一次浏览的页面

 //不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
 this.$router.replace('/index');
 this.$router.replace({name: 'routerNmae'});    //指定跳转到路由name

 this.$router.push('/index');   //通过push跳转
 this.$router.push({name: 'routerNmae'});   //通过push跳转,新增history记录
 
 // 命名的路由params
 router.push({ name: 'user', params: { userId: '123' }})-> /user/123
 
 // 带查询参数query,变成 /register?plan=private
 router.push({ path: 'register', query: { plan: 'private' }})

二级路由 — 路由嵌套

一般都用作导航

  • 1、依然在 路由.js 中import 页面路径
  • 2、在需要展示二级的 path中 配置 {path:'/', name:'index', meta:{title:'主页',}, component:index, children:[{path:'/index/xxx',name:"erjiLink",component:routerName}]}
  • 3、配置 redirect:'/默认显示路径' -- 重定向

导航守卫

完整的导航解析流程

全局守卫

全局前置守卫 使用更多(登录拦截) router.beforeEach((to, from, next) => { // ... })

路由独享的守卫

routes: [
    {
    path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...**进入该页面之前todo**
      }
    }  ]

组件内守卫

  • beforeRouteEnter:在渲染该组件的对应路由被 confirm 前调用,不能 访问 this。但是,next(vm => { // 通过 **vm** 访问组件实例 })
  • beforeRouteUpdate (2.2 新增):在当前路由改变,但是该组件被复用时调用
  • beforeRouteLeave:导航离开该组件的对应路由时调用

完整的导航解析流程(路由守卫)

导航被触发。
在失活的组件里调用离开守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

组件结构化

按照一定的结构组织,使得组件便于理解。

<template lang="html">
    <div class="Ranger__Wrapper">
        <!-- ... -->
    </div>
</template>

<script type="text/javascript">
  export default {
    // 不要忘记了 name 属性
    name: 'RangeSlider',
    // 组合其它组件
    extends: {},
    // 组件属性、变量
    props: {
        bar: {}, // 按字母顺序
        foo: {},
        fooBar: {},
    },
    // 变量
    data() {},
    computed: {},
    // 使用其它组件
    components: {},
    // 方法
    watch: {},
    methods: {},
    // 生命周期函数
    beforeCreate() {},
    mounted() {},
};
</script>

<style scoped>
  .Ranger__Wrapper { /* ... */ }
</style>

优化组件

检查所有的事件。子组件向父组件通信一般是通过事件来实现的,但是大多数的开发者更多的关注于 props 从忽视了这点。 Props向下传递,事件向上传递! 。以此为目标升级你的组件,提供良好的 API 和 独立性。

当遇到 props 和 events 难以实现的功能时,通过 this.$refs 来实现。 当需要操作 DOM 无法通过指令来做的时候可使用 this..$ref 而不是 JQuery , document.getElement,document.queryElement 。

提供组件 API 文档

在模块目录中添加 README.md 文件: 在 README 文件中说明模块的功能以及使用场景。对于 vue组件来说,比较有用的描述是组件的自定义属性即 API 的描述介绍。

状态管理器 教程

  • state: 存储数据
  • getter: 获取store 属性方法
  • mutation: 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,类似于事件。
  • action: Action 提交的是 mutation,而不是直接变更状态。

如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。 确实是如此—如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。

这个状态自管理应用包含以下几个部分:

state,驱动应用的数据源;
view,以声明方式将 state 映射到视图;
actions,响应在 view 上的用户输入导致的状态变化。
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,
那么相应的组件也会相应地得到高效更新。

改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation. 这样使得我们可以方便地跟踪每一个状态的变化.

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

通过 store.state 来获取状态对象,以及通过 store.commit 方法触发状态变更:

store简单状态管理起步使用

  • this.$store.state.products // 获取 store中的数据
  • getters:Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:
store.js 中定义

getters: {
  // ...1通过属性定义
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  },
  // ...2通过方法定义
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
我们可以很容易地在任何组件中使用它

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount; //通过属性访问
    store.getters.getTodoById(2) //通过方法访问 -> { id: 2, text: '...', done: false }
  }
}

mapGetters 辅助函数

仅仅是将 store 中的 getter 映射到局部计算属性:

  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
  ...mapGetters([
      'doneTodosCount',
      'anotherGetter'
    ]).
  }

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,类似于事件。

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})
//要唤醒 mutation handler
store.commit('increment')

登录成功之后重定向到redirect

watch: {
    $route: {
      handler: function(route) {
        this.redirect = route.query && route.query.redirect
      },
      immediate: true
    }
  },
  
  //登录成功方法里
  this.$router.push({ path: this.redirect || '/' })