VUE2相关

1、Vue的优点和缺点

Vue的优点:

  • 组件化开发,减少代码编写量

  • 数据双向绑定

  • 响应式界面

  • Vue使用路由不会刷新页面

  • 体积小,轻量化

  • 虚拟DOM

  • 运行效率高

  • 生态丰富、学习成本低

Vue的缺点:...

2、Vue生命周期

Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程

vue生命周期的作用

生命周期中有多个事件钧子,更好的控制整个Vue实例的过程中的各种逻辑

vue八个生命周期阶段

  • beforeCreate 创建前

  • created 创建后

  • beforeMount 载入前

  • mounted 载入后

  • beforeUpdate 更新前

  • updated 更新后

  • beforeDestroy 销毁前

  • destroyed 销毁后

第一次页面加载会触发的钩子

beforeCreate、created、beforeMount、mounted

DOM渲染在mounted周期中就已经完成

父子组件生命周期顺序

  • 父组件---beforeCreate

  • 父组件---created

  • 父组件---beforeMount

  • 子组件---beforeCreate

  • 子组件---created

  • 子组件---beforeMount

  • 子组件---mounted

  • 父组件---mounted

3、v-if 和 v-show 区别

1、实现方式:v-if是通过控制dom节点的存在与否,来控制元素的显隐; v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;

2、编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;

3、编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存后,然后再切换的时候进行局部卸载);v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;

4、性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

频繁切换,使用v-show较好;运行时条件很少改变,则使用v-if较好

4、v-if 和 v-for 优先级

v-for 的优先级要比 v-if 的优先级高

vue.js 源码种10997行

if (e1.staticRoot && !el.staticProcessed) {
  return genstatic(el,state)
} else if (el.once && !el.onceProcessed) {
  return genOnce(el, state)
}else if (el.for && !el.forProcessed) {
  return genFor(el, state)
} else if (el1.if && !el.ifProcessed) {
  return genIf(el, state)
}else if (el.tag === 'template' &&!el.slotTarget && !state.pre) {
  return genchildren(el, state) || 'void 0'
}else if (el.tag === 'slot') {
  return genSlot(el, state)
} else {'...'}

v-if 、v-for 不要写在同一个节点上,性能很差,如要配合使用,v-if 写在父节点上

5、props 和 data优先级

源码体现 :props ==>methods ==> data ==> computed ==>watch

6、Vue组件通讯

  • 父传子:props(不可修改)、this.$parent(可修改)、依赖注入(向下多级也可接收)、插槽

  • 子传父:$emit、插槽、this.$children

  • 兄弟通信:$emit、bus.js(新建bus工具类,利用 $emit 和 $on)、Vuex

  • 跨级通信:Bus、Vuex、provide/inject API、$attrs/$listeners

父传子:props

//父:
<Son :msg="str"></Son>
​
//子:
props:{
    msg: {
        type:String,        // 声明类型
        require:true,       //声明是否必需
        default:'default'   // 声明默认值
    },
}

父传子:插槽

//默认插槽
​
父:father.vue
    <son>你好</son>
​
子:son.vue
    <div>
        ...
        <slot/>     //不同父组件,传递不同值,展现不同结果
        ...
    </div>
//具名插槽
​
父:father.vue
    <son>
        <div slot='one'></div>
        <div slot='two'></div>
    </son>
​
子:son.vue
    <div>
        ...
        <slot name='one'/>
        <slot name='two'/>  
        ...
    </div>
//作用域插槽(vue2.6之后出现)
​
父:father.vue
    <son>
        <template v-slot:one>
            <div></div>
        </template>
        <template v-slot:two>
            <div></div>
        </template>
    </son>
​
子:son.vue
    <div>
        ...
        <slot name='one'/>
        <slot name='two'/>  
        ...
    </div>

子传父:插槽

//父:father.vue
<son>
    <template scope='params'>
        <div>{{params.one}}</div>
    </template>
    <vue slot-scope='params'>
        {{params.two}}
    </div>
</son>
​
//子:son.vue
<div>
    ...
    <slot :one='one' :two='two'/>
    ...
</div>
​
one:'str'
two:[ {a:4} ]

子传父:$emit

//子:
<button @click="cName">改变父组件的name</button>
​
methods: {
    cName(){
        this.$emit( 'hChange', 'Jack')
        //触发父组件中事件并传参
    }
}
//父:
<child @change="hChange"></child>
​
methods:{
    hChange(option) { 
        this.name = option
    }
}

兄弟间通信:$emit

//创建bus作为中转
import Vue from "vue" ;
export default new Vue;
//A组件
​
<button @click='btn'>按钮</button>
​
return { Str:"数据" }
methods:{
    btn(){
        bus.$emit( 'selectItem', this.Str )
    }
}
//B组件
​
created(){
    bus.$on( 'selectItem' ,(val)=>{
        console.log( val );
    })
}

  • 自定义事件:子向父通信

在父组件中,为子组件绑定一个自定义事件,可以用@也可以用$on,并且回调函数存在于父组件中。在子组件中用$emit触发自定义事件,$emit第一个参数是事件名,第二个参数是要传递的参数。

  • vuex:任意组件间的通信

数据会存放在state里面,可以在actions中发送ajax请求数据,在mutations中可以对数据进行处理。所有的组件都可以通过mapState拿到state中的数据。

  • 全局事件总线:任意组件间的通信

在main.js入口函数中,实例化vue时,在beforeCreate中注册全局事件总线$bus,那所有的组件实例对象都可以访问到$bus里的数据。

  • 消息订阅与发布:任意组件间的通信

7、computed methods watch

computed:计算属性,有缓存,其自定义的方法“xx”有返回值,可以直接{{xx}}使用,无需data-return返回,实时计算,多个属性影响一个建议使用computed

methods:方法属性,无缓存,进入页面就会触发,允许html{{ xx()}}方式执行

watch:监听属性,需要监听属性“xx”,以方法名的形式写入,参数newVal,oldVal等,当数据或路由发生改变时才会触发,单个属性影响一个使用watch

8、双向数据绑定原理

通过Object.defineProperty劫持数据发生的改变,如果数据发生改变了(在set中进行赋值的),触发update方法进行更新节点内容“{{str}}” ,从而实现了数据双向绑定

9、常用方法

  • ref

    //获取dom节点
    <div ref='box'></div>
    ​
    this.$refs.box
  • v-bind

        动态绑定,简写【:】,单向绑定

  • v-model

        双向绑定

  • v-on

        组件事件监听器,简写【@】

  • v-slot

        简写【#】

10、keep-alive

缓存组件,使用keep-alive会多俩个生命周期(activated、deactivated),提升性能

11、nextTick

用于获取最新dom的数据

当dom更新完毕,用于执行内部代码。使用普通方法可能获取到的值不是最新的,这是vue底层渲染机制导致的。nextTick() 通过异步的方式等待所有dom和数据更新完毕,再去获取值,保证获取到最新的值

使用场景:插件等。如new Swiper插件,获取当前元素的宽度或者高度,等dom都加载完毕再去获取宽度和高度

12、diff 算法

当数据发生变化时,vue更新节点

渲染真实DOM的开销是很大的,修改了某个数据,直接渲染到真实dom上会引起整个dom树的重绘和重排,如何只更新修改的那一小块dom而不更新整个dom,diff算法

先根据真实DOM生成虚拟DOM,当虚拟DOM某个节点的数据改变后会生成一个新的 vue节点,然后 新节点 和老节点 作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使 老节点 的值为 新节点

diff 的过程就是调用名为 patch 的函数,比较新旧节点,一边比较一边给真实的DOM打补丁

Vue的diff算法是对新旧两条虚拟DOM进行逐层比较并更新真实DOM

diff算法是平级比较,不考虑跨级的情况,采用 深度递归 + 双指针 的方式进行比较

  • 先比较是否是相同节点

  • 如果是相同节点比较属性(key、tag、input->type),并复用老节点

  • 然后比较子节点,以先对比两边,再交叉对比,再乱序对比的方式进行比较(头头、尾尾、头尾、尾头、乱序)

13、打包上线

修改路径:修改css、js资源访问路径,默认为“/”,修改为“./”,例vue-cli修改方式:

//根目录新建vue.config.js文件
module.exports = {
    publicPath: './',   //修改默认路径
    devServer:{         //设置propos代理,开发阶段解决跨域
      propos:'后端路径'
    }
}
import axios from 'axios'
export default {
  $axios(options) {
    let apiUrl = null;
    if (process.env.VUE_APP_ENV == 'dev') {
      apiUrl = options.url;
    } else {
      apiUrl = process.env.VUE_APP_BASE_API + options.url;
    }
    return axios({
      url: apiUrl
    })
  }
}//判断开发生产环境

前端自测项目采用hash模式,url路径默认带“#”字符

打包上线采用history模式 ,不带“#”,会出现空白页,告知后端需做重定向处理

Vue全家桶

1、Vue-Cli 构建

创建项目:vue2、vue3

打包项目:...

2、Vue-Router 路由

路由模式:history、hash

1、表现形态不同 ​ history : http: / / localhost:8080/ about ​ hash: http:/ / localhost :8080/# / about(端口号后)

2、跳转请求( http: / / localhost:8080/id===>不存在的路径“id”) ​ history 发送请求(404) ​ hash不会发送请求

3、打包后前端自测要使用hash,如果使用history会出现空白页

this.$router.push({
    name:“路由名字”,
    params:{},
    query:''
})
name 属性指定了目标路由的名称。定义路由时给路由配置对象设置的 name 属性。
​
params 属性用于传递路由参数,可以是一个对象,包含要传递的参数键值对。这些参数将被包含在 URL 中,可以在目标页面通过 $route.params 来获取。
​
query 属性用于传递查询参数,可以是一个字符串。这些参数将以查询字符串的形式附加在 URL 后面,可以在目标页面通过 $route.query 来获取。

params 和 query 都是在路由中传递参数的方式,但它们有一些区别,主要体现在以下几个方面:

传递方式:

  • params:通过 URL 的路径来传递参数,例:/users/123,以路径的形式体现

  • query:通过 URL 的查询字符串来传递参数,例:/users?id=123,以键值对和字符串的形式体现

参数格式:

  • params:通常使用对象形式传递参数,可以包含多个键值对。参数将直接作为 URL 的一部分,用于表示资源的唯一标识或者路由层级关系。

  • query:通常使用字符串形式传递参数,以查询字符串的形式附加在 URL 后面。参数是以键值对的形式存在,用于传递额外的信息、过滤条件等。

使用场景:

  • params:适合用于表示动态路由和页面间的层级关系。例如,在一个博客应用中,/posts/:id 可以表示不同文章的路由,其中 :id 可以作为 params 传递具体的文章编号。

  • query:适合用于传递额外的、可选的参数,如搜索关键字、过滤条件、排序方式等。例如,/search?q=apple&category=fruits 可以通过 query 传递搜索关键字和分类。

以对象方式传参时,如果我们传参中使用了params,只能使用name,不能使用path,如果只是使用query传参,可以使用path 。

路由跳转

...

路由传值

  • 显式

http://localhost:8080/about?a=1
传:
    this.$router.push({
        path: '/about',
        query: { a: 1 }
    })
​
接:  this.$route.query.a
  • 隐式

http://localhost:8080/about
传: 
    this.$router.push({
        name'About',
        params:{ a: 1 }
    })
    
接: this.$route.params.a

路由导航守卫

1、全局

beforeEach、beforeResolve、afterEach

2、路由独享

beforeEnter

3、组件内(少用,维护成本高)

beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

3、Vuex 状态管理

Vue状态管理工具,采用集中式存储管理应用的所有组件的状态

Vuex属性

State、Getters、Mutations、Actions、Modules

  • State-->data(数据)

  • Getters-->Computed(计算)

  • Mutations-->Methods(方法),同步

  • Actions-->Mutations,可写方法,提交的参数不同。提交的是Mutations,而不是直接变更状态,异步方法写在这里

  • Modules 把以上4个属性再细分,让仓库更好管理。建立不同的js文件,对不同类别的数据,方法等进行分类,然后引入到同一个js当中

Vuex是单向还是双向数据流

单向数据流,Vuex能被其他组件使用,不能被改,只能getter,无Setter

Vuex中的mutaitons和actions区别

  • mutaitons:都是同步事物

  • actions: 可以包含任意异步操作

    写入方法,在调试中,使用浏览器Vue插件查看数据变化可知

Vuex如何做持久化存储

本身无法持久化存储,解决方法:

  • localStorage

  • 插件(底层localStorage,更方便)

4、Axios 请求

        请求

        请求封装

        请求拦截

        请求优化

Vue操作

1、Axios和进度条

npm install axios@0.21.1

npm install nprogress@0.2.0

/* 
    对axios进行二次包装
    1. 配置通用的基础路径和超时
    2. 显示请求进度条
    3. 成功返回的数据不再是response, 而直接是响应体数据response.data
    4. 统一处理请求错误, 具体请求也可以选择处理或不处理
*/
import axios from 'axios'
import NProgress from 'nprogress'
// 引入进度条样式
import 'nprogress/nprogress.css'
​
// 配置不显示右上角的旋转进度条, 只显示水平进度条
NProgress.configure({ showSpinner: false }) 
​
//创建axios实例[创建出来的实例即为axios,只不过可以配置一些东西]
const service = axios.create({
  baseURL: "/api", // 基础路径
  timeout: 15000   // 连接请求超时时间
})
​
//请求拦截器:在发请求之前可以检测到,可以干一些事情
service.interceptors.request.use((config) => {
  // 显示请求中的水平进度条
  NProgress.start()
​
  // 必须返回配置对象
  return config
})
​
//响应拦截器:服务器的数据已经返回了,可以干一些事情
service.interceptors.response.use((response) => {
  // 隐藏进度条
  NProgress.done()
  // 返回响应体数据
  return response.data
}, (error) => {
  // 隐藏进度条
  NProgress.done()
​
  // 统一处理一下错误
  alert( `请求出错: ${error.message||'未知错误'}`)
​
  // 后面可以选择不处理或处理
  return Promise.reject(error)
})
​
//对外暴露二次封装的axios
export default service

2、前端代理解决跨域

根目录下的 vue.config.js 中配置,proxy 为通过新建代理服务解决跨域问题 封装 axios 时设置 baseURL 为 api ,所以所有的请求都会携带 /api

vue.config.js

module.exports = {
    //关闭eslint
    lintOnSave: false,
    devServer: {
        // true 则热更新,false 则手动刷新,默认值为 true
        inline: false,
        // development server port 8000
        port: 8001,
        //代理服务器解决跨域
        proxy: {
            //会把请求路径中的/api换为后面的代理服务器
            '/api': {
                //提供数据的服务器地址
                target: 'http://xxx',
​
            }
        }
    }
}

3、全局组件

全局的配置都需要在main.js中配置,在任一页面中直接使用,不需要导入声明

import Home from '@/pages/Home';
Vue.component(Home.name,Home);

4、代码改变页面自动刷新

根目录下vue.config.js文件设置

module.exports = {
    //关闭eslint
    lintOnSave: false,
    devServer: {
        // true 则热更新,false 则手动刷新,默认值为 true
        inline: true,
        port: 8001,
    }
}

5、undefined细节

访问undefined的属性值会引起红色警告,可以不处理,但是要明白警告的原因。

赋值的时候,在后面加一个||条件。即当属性值undefined时,会返回||后面的数据,这样就不会报错。 如果返回值为对象加||{},数组:||[ ]

6、失焦事件

blur与change事件在绝大部分情况下表现都非常相似,输入结束后,离开输入框,会先后触发change与blur,唯有两点例外。

(1) 没有进行任何输入时,不会触发change 在这种情况下,输入框并不会触发change事件,但一定会触发blur事件。在判断表单修改状态时,这种差异会非常有用,通过change事件能轻易地找到哪些字段发生了变更以及其值的变更轨迹。

(2)输入后值并没有发生变更 这种情况是指,在没有失焦的情况下,在输入框内进行返回的删除与输入操作,但最终的值与原值一样,这种情况下,keydown、input、keyup、blur都会触发,但change依旧不会触发。

@click.prevent,它可以阻止自身默认事件的执行。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值