vue的笔记

vue的特性

1.数据驱动试图: 数据发生变化会驱动视图自动更新
2.双向数据绑定: 在页面或者data里面修改数据都会相对应的改变

vue指令

数据绑定指令(内容渲染指令)
  • v-text 的缺点:会覆盖元素内部的内容
  • v-html 的作用:可以把带标签的指令渲染到页面上
  • {{}} 开发中经常用这个
  • v-model 输入框的双向数据绑定指令
属性指令
  • v-bind
  • 简写形式 : (英文输入法模式哦)
事件绑定指令
  • v-on
  • 简写形式 @
条件指令
  • v-show
  • v-if
循环指令
  • v-for(item in 数据源)
computed 计算属性

计算属性默认只能获取而不能修改,需要修改的话就需要通过setter来改变
读取就使用: getter 修改的话: setter

filter 过滤器属性

只能用在 双花括号插值v-bind 这两个地方

watch 监听属性

键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象

生命周期函数
  • beforeCreate
    • 此时data 和 methods之类的都没创建出来,在加载实例时触发
  • created
    • 此时实例创建完成,可以访问 data methods computed等方法和数据,但是没有挂载DOM,一般都在这个阶段发送 axios 请求数据
  • beforeMount
    • 这个阶段已经完成了 模板的编译,但是还没有渲染到页面上
  • mounted
    • 这个阶段 页面已经渲染完成,页面可以看到演示了
  • beforeUPdate
    • 这个阶段 页面的某些data数据发生变化,是一种最新的状态,但是,页面的数据还是旧的,没有渲染上去。 (有时候我们希望某些数据渲染延迟一会,这个时候就可以用**nextTick()**方法来进行延迟更新)
  • updated
    • 这个阶段 data中的数据和页面上的数据都是最新的了,页面重新渲染完成
  • beforeDestroy
    • 这个阶段,VUE开始销毁了,但是,此时还没销毁,实例依旧可以使用,this仍然可以获取实例
  • destroyed
    • 这个阶段,实例销毁完成this获取不到实例,所有事件监听都会移除
      生命周期表

vue修饰符

Vue修饰符

  • lazy

    • 作用: 改变输入框的值时 value不会改变,但是,一旦输入框失去焦点,v-model.lazy绑定的值就会改变
    <input type="text" v-model.lazy="value">
    <div>{{value}}</div>
    
    data(){
      return{
        value:'222'
      }
    }
    

    图片

  • trim

    • 作用:去掉首位的空格
    <input type="text" v-model.trim="value">
      <div>{{value}}</div>
    
    data(){
      return{
        value:'222'
      }
    }
    

    图片

  • number

    • 将值转换成数字类型。注意:先输入数字的话,只取前面数字部分/先输入字母的话,number将会无效
  • stop

    • 作用:阻止冒泡
    <div @click="clickEvent(2)" style="width:300px;height:100px;background:red">
      <button @click.stop="clickEvent(1)">点击</button>
    </div>
    
    methods: {
            clickEvent(num) {
                不加 stop 点击按钮输出 1 2
                加了 stop 点击按钮输出 1
                console.log(num)
            }
        }
    
  • self

    • 作用:只有点击事件绑定的本身才会触发事件
    <div @click.self="clickEvent(2)" style="width:300px;height:100px;background:red">
      <button @click="clickEvent(1)">点击</button>
    </div>
    
    methods: {
            clickEvent(num) {
                不加 self 点击按钮输出 1 2
                加了 self 点击按钮输出 1 点击div才会输出 2
                console.log(num)
            }
        }
    
  • once

    • 作用:事件只执行一次
    <div @click.once="clickEvent(2)" style="width:300px;height:100px;background:red">
      <button @click="clickEvent(1)">点击</button>
    </div>
    
    methods: {
            clickEvent(num) {
                不加 once 多次点击按钮输出 1
                加了 once 多次点击按钮只会输出一次 1 
                console.log(num)
            }
        }
    
  • proevent

    • 作用: 阻止默认事件
    <a href="#" @click.prevent="clickEvent(1)">点我</a>
    
    methods: {
            clickEvent(num) {
                不加 prevent 点击a标签 先跳转然后输出 1
                加了 prevent 点击a标签 不会跳转只会输出 1
                console.log(num)
            }
        }
    

Vuex的原理

含义:vuex是一个专门为vuex.js应用程序开发的状态管理模式,每一个Vuex应用的核心是store(仓库),“store”基本上就是一个容器,它包含着应用中大部分状态。

  • Vuex的状态存储是响应式的,当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应的更新
  • 改变store中的状态的唯一途径就是通过Mutation。这样使得我们可以方便地跟踪每一个状态的变化
  • 主要包括一下几个模块:
    • State:定义了应用状态的数据结构,可以在这里设置默认初始状态
    • Mutation: 这是我们修改State中数据状态的唯一路径
    • Action:在这里面一些异步操作,然后提交到Mutation中,再由其修改State中的数据
    • Getter:允许组件从Store中获取数据,
    • Module:允许将单一的Store拆分成多个Store且同时保存在单一的状态树中

VueX的使用

  1. 安装:npm i vuex --save
  2. 新建一个store文件夹,写入一下基本代码格式
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state:{
    //这里面写 Vue实例里 data数据一样
  },
  mutations:{
    //这里面写修改 state 里面数据的方法
  }
})
  1. 入口函数main.js引入Store

原理:

通俗讲:利用了 全局混入Mixin,将我们所创建的store对象,混入到每一个Vue实例中。

vuex数据持久化方法

这个还没写

面试题部分

Vue的优点和缺点

  • 优点:
    • 渐进式,
    • 组件化,可以重复利用
    • 简单易学,中文文档,不存在语言障碍,易于学习和理解
    • 轻量级,只关注视图层,是一个构建数据的试图集合
    • 虚拟dom,
    • 双向数据绑定,
    • 单页面路由,
    • 数据和试图是分开的
  • 缺点:首屏加载时间长

Vue的虚拟DOM有什么好处

  1. 虚拟dom比真实dom体积小,操作是相对来说消耗性能少,如果说在页面上删除某个dom,会引起页面的重绘,影响后边的布局
  2. 虚拟dom进行频繁的修改,然后一次性笔记并修改真实DOM中需要修改的部分,最后并在真实DOM中进行回流和重绘,减少过多DOM节点的回流和重绘,
  3. 真实DOM频繁的回流1与重绘会降低效率,

MVVM是什么?

  • MVVM的理解:
    • MVVM由Model、View、ViewModel三部分构成,Model层代表数据模型,可以在Model中定义数据修改和操作的业务逻辑;View代表UL组件,它负责将数据模型转换成UL展现出来;ViewModel是一个同步View和Model的对象;ViewModel通过双向数据绑定把View层和Model层连接起来,它们之间的同步工作完全是自动的,无需人为干涉,开发者只需要关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,数据状态维护完全由MVVM来统一管理

为什么VUE组件中的data必须是一个函数,而Vue实例却可以是个对象

因为组件是用来复用的,且JS里对象是引用关系,如果组件中data是一个对象,那么这样作用域没有隔离,子组件中的data属性值会被互相影响,如果组件中dara选项是一个函数,使用的是data()函数,data()函数中的this指向的是当前实例本身,就不会相互影响了,组件实例之间的data属性值不会互相影响。而new Vue实例 是不会被复用的,因此不存在引用对象的问题

SPA是什么?对它的理解,它的优缺点

  • 是什么?
    • SPA仅在Web页面初始化时加载相应的HTML、js和CSS
    • 一旦页面加载完成,SPA不会因为用户的操作进行页面的重新加载或跳转
    • 页面的变化是利用路由机制实现HTML内容的变换,避免了页面的重新加载
  • 优点
    • 用户体验好,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
    • 相对减轻了服务器的压力
  • 缺点
    • 初次加载消耗的时间多
    • 不能使用浏览器的前进后退功能,由与单页应用在一个页面中显示所有的内容,所有无法前进后退
    • 不利于搜索引擎检索:由于所有内容在一个页面替换显示,所有在SEO上有着天然弱势

SPA首屏加载速度慢怎么解决?

首屏时间☞浏览器从响应用户输入网址到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容。

  • 加载慢的原因:
  • 网络延时问题
  • 资源文件体积是否过大
  • 资源是否重复发送请求去加载了
  • 加载脚本的时候,渲染内容堵塞了
  • 常见的几种首屏优化方式:
  • 减小入口文件体积
    • 路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由请求的时候单独打包路由,使得入口文件变小
    • 在配置路由的时候,采用动态路由加载路由的形式
  • 静态资源本地缓存
    • 合理利用localStorage,把一些静态资源缓存到本地,
  • UL框架按需加载
  • 图片资源的压缩
    • 对页面上使用道德icon,可以使用在线字体图标,图片之类的可以使用雪碧图,将众多小图标合并到同一张图上

Vue数据双向绑定原理

Vue的数据双向绑定是采用数据劫持发布订阅来实现的。就是对象内部使用object.defineproperty将各个已经存在的属性添加**setter(),getter()**来进行劫持和监听,当监听的对象属性有变化,就拿到最新的值并且通知订阅者,订阅者拿到最新的值来根据指令模板替换需要修改的数据部分,以及绑定相应的更新函数,从而更新视图
数据双向绑定实现原理

为什么只对对象劫持,而数组就直接进行方法重写?

因为对象最多也就几十个属性,拦截起来数量不多,但数组就不同了,数组可能会有几百上千组数据,拦截起来非常消耗性能,所以直接重写数组原型上的方法是比较省性能的方法

描述下vue从初始化页面—修改数据–刷新页面UL的过程

当Vue进入初始化阶段时,一方面Vue会遍历data中的属性,并用Object.defindProperty将它劫持监听成 get/set 的形式,另一方面Vue的指令编辑器 Compiler会对元素节点的各个指令进行解析,初始化视图,并订阅Watcher来更新视图,此时Watcher会将自己添加到消息订阅器Dep中,此时初始化完毕。
当数据发生变化时,触发Observer中的setter方法,立即调用Dep.notify(),Dep这个数组开始遍历所i有的订阅者,并调用其update方法,Vue内部再通过dif算法,patch相应的更新完成对订阅者视图的改变
Vue双向绑定原理

组件之间的传值方式

  • 父组件传值给子组件使用自定义属性,子组件使用props进行接收
// 父组件:
<div :sisui="xfq"></div>
data(){
  return{
    xfq:{
      这里写要传给子组件的数据
    }
  }
}
// 子组件
<p>{{sisuiL}}</p>
props:{
  sisuiL{
    default:这里是写一些默认值的
    type:这里写传过来的数据类型
    requires:这里写 true/false 是用来确定这个是不是必须填的数据
  }
}
  • 子组件传值给父组件使用自定义事件,子组件使用**$emit + 事件**对父组件进行传值
// 子组件
methods:{
  add(){
    this.$emit('sisui',要传的数据)
  }
}
// 父组件
<div @sisui="getSisui"></div>
methods:{
  getSisui(val){
    console.log(val)
  }
}
  • 使用**$refs**获取组件实例,从实例里面获取数据
  • 使用Vuex进行状态管理
  • 使用全局事件总线eventBus。使用步骤: 创建eventBus.js模块,向外暴露 vue的实例对象。数据发送方通过:bus. e m i t ( ′ 事 件 名 称 ′ , 要 发 送 的 数 据 ) ∗ ∗ 。 数 据 接 收 方 通 过 : ∗ ∗ b u s . emit('事件名称',要发送的数据)**。数据接收方通过:**bus. emit(,)bus.on(‘传过来的事件名称’,事件处理函数)
// 1.创建文件(eventBus )里面一个 空的Vue实例 向外共享实例对象
import Vue from 'vue'
export default new Vue()  //向外共享实例对象
// 数据发送方
// 导入 空的Vue实例
import bus from '@/eventBus.js'
methods:{
  add(){
    bus.#emit('sisui',要发送的数据)
  }
}
// 数据接收方
// 导入 空的Vue实例
import bus from '@/eventBus.js'
methods:{
  add(){
    bus.$on('sisui'val=>{
      这里要记得使用 箭头函数 哦
      接收的数据赋给本组件的某个
    })
  }
}

为啥不可以修改父组件传递的Prop?要是想要强行修改该咋办

  • 为什么不能修改:
    • Vue提倡单向数据流,即父级props的更新会流向子组件,但是反过来不行,这是为了防止意外的改变父组件状态,使得应用的数据流变得难以理解。如果这样做了,Vue会在浏览器的控制台中发出警告
  • 修改的方法:
    • .sync修饰符

路由的两种模式:hash模式和history模式

  • has :通过 #号 后面的内容更改触发hashchange事件实现路由切换
  • history :通过 pushStatereplaceState 这两个API可以改变 url,但是不会发送请求

Vue中如何使用自定义组件

    1. 在components目录中新建组件文件
    1. 在需要使用组件的页面中导入
    1. 在需要用组件的页面的compontents属性上注册这个导入的组件
    1. template视图上像使用标签一样使用组件

v-if 和 v-show 的区别

  • v-if 是通过控制dom元素的删除和生成来实现隐藏的,每一次显示和隐藏都会使组件重新跑一遍生命周期,因此,决定了组件的生成和销毁
  • v-show 是通过控制dom元素的css样式来实现显示和隐藏的,不会被销毁
  • 频繁或者大数量的显示和隐藏使用v-show,否则就使用v-if

computed 和 watch 有什么区别

computed适合在模板渲染中,某个值是依赖了其它响应式对象甚至是计算属性计算而来,而watch适合监听某个值的变化去完成一段复杂的业务逻辑

  • computed 是依赖已有的变量来计算一个木匾变量,大多数情况都是多个变量凑在一起计算出一个变量,并且computed具有缓存,依赖值不变的情况下会之间读取缓存进行复用,但是,computed不能进行异步操作
  • watch 是监听某一个变量的变化,并执行相应的回调函数,通常时一个变量的变化决定多个变量的变化,watch可以进行异步操作

computed 和 methods 的区别

  • 相同点:
    • 如果做为模板的数据显示,二者能实现响应的功能,唯一不同的是methods定义的方法需要执行
  • 不同点:
    • computed 会基于响应数据缓存, methods 不会缓存
    • computed 是属性调用,而 methods 是函数调用

为什么 v-for 和 v-if 不建议在同一标签使用?而我就是想要使用在一起,有什么好方法

v-forv-if在同一节点使用时,v-for的优先级比v-if更高,意味着v-if将分别重复运行于每个v-for循环中,如果要遍历的数组很大,而真正要展现的数据很少是,这样会造成很大的性能浪费

<div v-for="item in [1,2,3,4,5,6,7]" v-if="item !== 3">{{item}}</div>

上面的写法会将7个元素都遍历出来,然后在一个个的判断是否为3,并把3给隐藏掉,这样操作渲染了无用的3节点,增加无用的dom操作,建议使用computed来解决

<div v-for="item in list">
{{item}}
</div>

computed(){
    list(){
      return [1,2,3,4,5,6,7].filter(item => item !== 3)
    }
}

不需要响应式的数据应该怎样处理

在开发中有些数据,从始至终都未曾改变过,这种死数据,那也就不需要对其做响应式处理,不然只会做一些无用功消耗,,会消耗大量性能

  • 方法一:将数据定义在 data 之外
data(){
  //不需要响应式的数据,比如一些表单校验之类的
  //  写在外面的话别忘了 this 这个玩意,不然会获取不到的哈
  this.数据名 = {数据值}
  this.数据名 = {数据值}
  this.数据名 = {数据值}
  return{
    //需要响应式的数据
  }
}
  • 方法二: 在data里面写 object.freeze()
data(){
  return{
    数据名:Object.freeze(数据值)
    数据名:Object.freeze(数据值)
    数据名:Object.freeze(数据值)
    数据名:Object.freeze(数据值)
  }
}

watch有哪些属性

watch:{
  add(){
    handler(){
      //执行回调
    },
    deep:true  //是否进行深度监听
    immediate: true  // 是否页面一加载就执行 handler的回调函数
  }
}

父组件 和 子组件 生命周期钩子执行顺序是什么

  • 渲染过程
    父组件 挂载完成一定是在等 子组件 都挂载完成后,才算父组件挂载完成,所以父组件的mounted在子组件moutend之后
    顺序:父beforeCreate --> 父created --> 父beforeMount --> 子beforeCreate --> 子created --> 子beforeMounte --> 子mounted -->父mounted
  • 子组件更新过程:
      1. 影响到父组件:父beforeUpdate -->子beforeUpdate --> 子updated --> 父updated
      1. 不影响父组件:子beforeUpdate --> 子updated
  • 父组件更新过程
      1. 影响到的子组件:父beforeUpdate -->子beforeUpdate --> 子updated --> 父updated
      1. 不影响道德子组件:父beforeUpdate --> 父updated

对象新属性无法更新视图,删除属性无法更新视图,为什么?怎么办?

  • 原因:object.defineProperty在对数据进行劫持的时候没有把属性一起劫持
  • 解决办法:
    • 对象新属性无法更新视图:使用Vue. s e t ( o b j , k e y , v a l u e ) ∗ ∗ , 组 件 中 ∗ ∗ t h i s . set(obj,key,value)**,组件中**this. set(obj,key,value),this.set(obj,key,value)
    • 删除属性无法更新视图:使用Vue. d e l e t e ( o b j , k e y ) ∗ ∗ , 组 件 中 ∗ ∗ t h i s . delete(obj,key)**,组件中**this. delete(obj,key),this.delete(obj,key)

自定义指令

通过 vue.directive()方法注册组件
指令定义函数提供了几个钩子函数:

  • bind: 只调用一次,指令第一次绑定到元素时调用,(这个时候还没插入dom),在这里可以进行初始化设置(一般进行样式之类的操作)
  • inserted:被绑定元素插入父节点时调用(一般进行js相关的操作)
  • update所在组件Vnode更新时调用,但是可能发生在其子元素的Vnode更新之前
  • computedUpdate:所在组件的Vnode及其子元素的Vnode全部更新之前
  • unbind:只调用一次,指令与元素解绑的时候调用

插槽的使用以及原理

插槽(Slot)是Vue为组件的封装者提供的能力,允许开发者在封装组件的时候,把不确定的、希望由用户指定的部分定义为插槽

  • 默认插槽
    • 没有设置 name属性,默认使用 default
  • 具名插槽
    • 设置了一个name属性
  • 作用域插槽
    • 在组件上的属性,可以在组件元素内使用

说说nexTick的用处

在下次DOM更新循环结束之后执行延迟回调(相当于原生js的setTimeout延时定时器方法)。在修改数据后立即调用这个方法,获取更新后的DON。
获取更新后的DOM言外之意是指什么操作需要用到更新后的DOM而不能使用更新前的DOM会出问题,

什么时候需要用到**nextTick()

  • 由于created()钩子函数执行的时候,DOM其实还没有进行任何渲染,生命周期钩子还没走到mounted 钩子, **而偏偏此时你需要对 DOM 进行操作,此时就可以用*nextTick()*来执行,这样回调函数在 DOM 更新完成后就会调用

route 和 router 的区别

  • router是Router的实例,相当于一个全局的路由器对象,里面包含很多的属性和子对象,经常用来跳转链接之类的
  • route相当于当前正在跳转的路由对象,可以从里面获取到路由的基本信息,携带的参数等

动态路由

路径参数使用“:”标记,冒号后面填我们传入的参数,可以通过this.$router.params查看得到路由参数数据。

嵌套路由

一层路由里面套着子路由,子路由通过children来包含着

const router = new VueRouter({
  routes:[
    {
      path:'路径',
      component:()=>import('文件路径'),
      children:[
        {
          // 在这写子路由
        }
      ]
    }
  ]
})

路由重定向

通过redirect来对页面进行重新定向(比如一个组件有两个子路由页面,当我们进入这个组件页面的时候,通过redirect来设置一个默认展示路由页面)

路由的几种钩子函数

  • 前置路由守卫
    • **beforeEach(to,from,next)**在路由跳转的时候触发,
    router.beforeEach(to,from,next) =>{
      // to 代表要去的路由
      // from 代表从哪个路径跳转过来的,相当于上一个路由
      // next 守卫通过next控制下一步的跳转
    }
    
  • 后置路由守卫
  • 路由独享的导航钩子
  • 组件内守卫钩子

项目优化性能系列

代码层面的优化

  • 1.1 v-if 和 v-show 区分使用场景
  • 1.2 computed 和 watch 区分使用场景
  • 1.3 v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
  • 1.4 图片资源懒加载
    • 做法:通过 vue-lazyload插件
    // 第一步  安装插件
    npm install vue-lazyload --save-dev
    // 第二步  在入口文件 man.js 中引入并使用
    import VueLazyload from 'vue-lazyload'
    Vue.use(VueLazyload)
    // 第三步  在vue文件中将 img 标签的 src 属性直接改为 v-lazy ,从而将图片显示方式更改为懒加载方式显示
    <img v-lazy="图片路径">
    
  • 1.5 路由懒加载
  • 1.6 第三方插件的按需导入

Vue项目如何解决兼容性问题

  1. 安装 babel-polyfill 模块
  2. 在 main.js中引入
  3. 在 webpack.base.comf.js 中配置
  4. 在index.html中强制浏览器默认渲染最高版本内核
// 1. 安装 babel-polyfill 模块
npm install -- save babel-polyfill
// 2. 在 main.js中引入
import 'babel-polyfill'
// 3. 在 webpack.base.comf.js 中配置
module.exports = {
  ....
  entry:{
    app:["babel-polyfill","./src/main.js"]
  }
  ....
}
// 4. 在index.html中强制浏览器默认渲染最高版本内核
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

导入

Vue项目如何解决兼容性问题

  1. 安装 babel-polyfill 模块
  2. 在 main.js中引入
  3. 在 webpack.base.comf.js 中配置
  4. 在index.html中强制浏览器默认渲染最高版本内核
// 1. 安装 babel-polyfill 模块
npm install -- save babel-polyfill
// 2. 在 main.js中引入
import 'babel-polyfill'
// 3. 在 webpack.base.comf.js 中配置
module.exports = {
  ....
  entry:{
    app:["babel-polyfill","./src/main.js"]
  }
  ....
}
// 4. 在index.html中强制浏览器默认渲染最高版本内核
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曾不错吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值