【前端高频面试题——精简系列2】

Vue常见的指令有哪些,有什么用

指令 解释
v-model 多用于表单元素双向数据绑定
v-bind 动态数据绑定,简写为冒号
v-on 事件绑定,简写为@
v-for 动态渲染
v-once 能执行一次性地插值,当数据再次改变时,插值处的内容不会更新
v-show 动态渲染元素的显示与隐藏
v-if 动态渲染和删除元素
v-else 和 v-if 搭配使用
v-else-if 同上
v-html 动态渲染节点的html内容,原内容会被覆盖,可以解析富文本
v-text 动态渲染节点的文本内容,原内容会被覆盖,不可以解析富文本

还有一种是自定义指令,后续补上

v-once让我想起了,事件修饰符,知道事件修饰符吗?

事件修饰符分五种:

.once     只发生一次
.self     只发生本身
.cuptrue  设置为捕获
.prevent  阻止默认事件
.stop     阻止冒泡
<button @click.once="clickFun">点击一次事件</button>

在页面展示数据的几种方式?

  1. v-text 只识别文本不解析富文本
  2. v-html 能解析富文本
  3. { {}} 插值表达式

双向数据绑定的原理

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

Vue3版本:使用 ES6 的 Proxy 作为其观察者机制,取代之前使用的Object.defineProperty。
因为Object.defineProperty方法存在一定的局限性,比如它无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。

Object.defineProperty缺陷
对象属性新增删除无法检测,导致视图不更新
数组的索引直接设置一个数组项无法检测,例:vm.items[indexOfItem] = newValue,新增索引也无法检测,导致视图不更新

路由的跳转和传参有哪几种方式

router-link 不带参数

 <div id='app'>
    <router-link to="/index" tag="div">去首页</router-link>
    <!-- 5.预留显示位置 -->
    <router-view></router-view>
  </div>

router-link 带参数

<router-link to="/index/login/personal?id=1&name=张三" tag="button">去个人中心页</router-link>

<router-link :to=`/index/login/personal/${id}/${name}` tag="button">去个人中心页</router-link>

<router-link :to="{name:'geren',params:{id,name}}" tag="button">去个人中心页</router-link>



函数式跳转 带参数和 不带参数

toIndex() {
    this.$router.push({ path: '/index' })
    this.$router.push('/index')
  },
toMine() {
  this.$router.push({
    name: "my",
    params: { userid: "哈哈哈" }
  })
},


组件间的通讯方式有哪些

父子组件之间的通信,通过 props 传递,(父传子)
通过 $emit 触发自定义事件 (子传父)
使用 ref获取组件方法(给组件起个名字,获取组件)
事件总线(this.$EventBus.$emit)
Vuex(常用)
本地缓存

Provide 与 Inject (vue3)
通过 $parent 或 $root
attrs 与 listeners

扩展: 事件总线

  1. 定义事件总线
 
import Vue from 'vue'
import App from './App.vue'
 
Vue.config.productionTip = false
 
//给Vue绑定属性
Vue.prototype.xyz=100;
// Vue.prototype.$EventBus=vm
 
new Vue({
  beforeCreate(){
  //安装事件总线
  Vue.prototype.abc=900;
  Vue.prototype.$EventBus=this
 },
  render: h => h(App),
}).$mount('#app')

向总线发送事件 this.$EventBus.$emit(发送事件名,传递参数)
<!--  -->
<template>
  <div id="demo01">
    <h1>Demo01组件</h1>
    <h2>从Demo02接受的收据:{
   
   {msg}}</h2>
    <button @click="fasong">发送数据给Demo02</button>
  </div>
</template>
 
<script>
export default {
      
      
  name: "Demo01",
  data () {
      
      
    return {
      
      
      msg: ''
    }
  },
  methods: {
      
      
    test01 (data) {
      
      
      console.log(data);
      this.msg = data
    },
    fasong () {
      
      
      this.$EventBus.$emit("send", "我是Demo01页面");
    }
  },
  mounted () {
      
      
    // console.log(this);
    // 2.接受全局的haha事件
    this.$EventBus.$on('haha', this.test01)
  }
}
</script>
<style scoped>
#demo01 {
      
      
  background-color: red;
  padding: 20px;
  margin-bottom: 20px;
}
</style>

 通过this.$EventBus.$on接收,this.$EventBus.$on(事件名,参数)
<!--  -->
<template>
  <div id="demo02">
    <h1>Demo02组件</h1>
    <button @click="sendData">发送事件给Demo01</button>
    <h2>从Demo01接受的收据:{
   
   {msg}}</h2>
  </div>
</template>
 
<script>
export default {
      
      
  name: "Demo02",
  data () {
      
      
    return {
      
      
      msg: ''
    }
  },
  methods: {
      
      
    sendData () {
      
      
      // 触发全局的haha事件
      this.$EventBus.$emit("haha", '老王')
    },
    display (data) {
      
      
      console.log(data);
      this.msg = data
    }
  },
  mounted () {
      
      
    // console.log(this.abc);
    console.log(this.$EventBus);
    this.$EventBus.$on("send", this.display)
  }
}
</script>
<style scoped>
#demo02 {
      
      
  background-color: blue;
  padding: 20px;
}
</style>

谈一谈对路由守卫的理解

路由守卫是路由在跳转前、后过程中的一些钩子函数,这些函数可以让你操作一些其他的事,在后台管理中设置权限时经常看到,在实现路由跳转前校验是否有权限,有权限就可以通过,反之就会被执行其他操作,如返回首页。
创建全局守卫:

const router = createRouter({ ... })

router.beforeEach((to, from) => {
  // ...
  // 返回 false 以取消导航
  return false
})

谈一谈对Vuex的理解

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。

Vuex有五大核心概念:

State :提供唯一的公共数据源
Mutations :用于变更state中的数据,必须是同步函数
Actions:用于变更state中的数据,但不能直接修改,需要通过context.commit()调用mutation,且可以包含任意的异步操作
Modules :用于模块化导入其他store
Getter : Getter用于对 store 中的数据进行加工处理后形成新的数据,类似 Vue 中的计算属性。Getter不会修改store中的数据,而是起到一个包装的作用。Store 中的数据发生变化,Getter的数据也会跟着变化。
Vuex解决了多组件之间状态共享的问题,组件间不用再把数据互相传来传去了,维护了单向数据流的简洁性。

想详细了解的,后续作者会发

谈一谈对混入mixin的理解

mixin混入就像共用的业务逻辑,可以混入到组件中去,但是组件之间不受影响;
原理是:将一样的数据,逻辑,进行提炼,单写一个mixin对象,它可以向其他组件一样,有数据,方法,声明周期。再导入的地方进行合并的方式显示,mixin的优先级低,优先展示父组件的数据,方法。
优点:降低耦合性,提高复用率,书写简介,便于维护

原文:因为babel@5支持了这种错误的写法,帮忙做了抹平。所以如果你用babel进行转码,那么即使你是这么写的import { c3 } from ‘./test’;,也能正常输出,尽管它本应该输出的是undefined。
但是这个特性会导致很多的混淆,所以在babel@6中已经干掉了这个特性,这就导致了兼容性问题。如果还想让babel继续有这种特性,可以使用babel-plugin-add-module-exports库。

大致就是es5这样写的时候语法规范为你处理抹平,但不支持这么写。
所以在es6的时候就不让你这么写,只能直接导出对象

一般会写一个mixin的文件夹,里面写minxin.js文件

在这里插入图片描述

mixin的写法举例:

es5的写法

const mixin= {
    
    
    data() {
    
    
        return {
    
    
            name: '初始名字:张三',
            mixinMsg: 'mixinMsg'
        };
    },
    methods: {
    
    
        // 获取mixin中的msg
        getMixinMsg() {
    
    
            alert(
                '我是mixin.js中的getmsg方法,mixinmsg的数据是' + this.mixinMsg
            );
        },
        // 获取home中的homeMsg
        getHomeMsg() {
    
    
            alert(
                '我是mixin.js中的getHomeMsg方法,HomeMsg的数据是' + this.homeMsg
            );
        }
    },
    created() {
    
    
        alert('在mixin中vue的data、生命周期、方法等都可以使用');
    }
};

export default mixin;

es6的写法

报错信息 大致有component报错,和babel报错,都是告诉你,在es6中不让这么写

export  const mixin = {
    
    
  data() {
    
    
    return {
    
    
      msg: '50'
    }
  },
  methods: {
    
    
    clickFun() {
    
    
      this.msg++;
      console.log(this.msg, 111111111)
    }
  },
}

mixin花括号一定加上,语法规范 mixins是属性规定,导入的mixin可以随意写
就跟vue3中的watch,created一样

</template>
  <div>
    <button @click="clickFun">点击获取mixin数据</button>
    {
   
   { msg }}
    {
   
   { msg }}
  </div>
</template>

<script>
import {mixin} from '@/mixin/mixin';//mixin路径

export default {
  mixins: [mixin],
}

mixin和组件的区别

本质上:

  • . 单纯组件引用:
    父组件 + 子组件 >>> 父组件 + 子组件
  • . mixins:
    父组件 + 子组件 >>> new父组件

有点像注册了一个vue的公共方法,可以绑定在多个组件或者多个Vue对象实例中使用。另一点,类似于在原型对象中注册方法,实例对象即组件或者Vue实例对象中,仍然可以定义相同函数名的方法进行覆盖,有点像子类和父类的感觉。

方法的覆盖
组件的方法覆盖mixins方法
如果在引用mixins的同时,在组件中重复定义相同的方法,则mixins中的方法会被覆盖。

谈一谈对插槽的理解

slot是组件内的一个占位符,主要的作用就是拓展组件的复用性,让我们在重复使用一个组件的时候可以通过少量的修改就达到复用的效果。

插槽分为具名插槽和默认插槽,默认插槽直接在子组件中书写slot后,再在子组件标签中传递需要的html结构即可,具名插槽有两种写法:

具名插槽写法一(标签法):

//父组件
<Category title="美食">
	<ul slot="foods">
	   <li v-for="(item,key) in foods" :key="key">{
   
   {item}}</li>
	</ul>
</Category>

//子组件
<h3>{
   
   {title}}分类</h3>
<slot name="foods">默认显示内容</slot>     /*给插槽取名*/

具名插槽写法二(template法):

<template v-slot:foods>
    <ul>
      <li v-for="(item,key) in foods" :key="key">{
   
   {item}}</li>
  </ul>
</template>

还有一种 scope 作用域插槽,这里不做注解,详情在此原文

什么是跨域,如何解决

什么是跨域?
浏览器有个安全策略,“同源策略”是只有协议,域名,端口都一样的时候,才能成功。主要用于隔离潜在恶意文件的关键安全机制。
浏览器从一个域名的网页去请求另一个域名的资源时,协议,域名,端口任意不同即为跨域。

如何解决?

  1. 后台直接不做限制,放开所有请求。优点:方便;缺点:显而易见的不安全;
  2. 配置代理,服务器和服务器之间不会发生同源策略
  3. JSONP
    基本原理:同源策略只对ajax请求有限制,非ajax请求无限制,非ajax请求(如:form表单请求、标签属性请求,a标签的href,img标签的src,script标签的src)不会被同源策略拦截,所以使用script标签的src属性发起的跨域请求不会被同源策略拦截。

配置代理:Proxy
首先在项目根目录下创建一个vue.config.js文件,然后在其中添加以下代码:

// vue.config.js for [email protected]
module.exports = {
    devServer: {
        proxy: {
        	// 代理的名称,一般以这种格式命名,当然你也可以随便起
            '/xxx-api': {
                target: 'http://1.111.xx.123:3000',  // 后台接口的协议、域名、端口号
                changeOrigin: true,  //是否跨域
                pathRewrite: {
                    '^/xxx-api': ''//路径重写
                    //如果不重写,则请求时的路径中会带有这个/xxx-api
                }
            },
        }
    }
};

谈一谈封装请求的心得

封装请求可以提高程序的复用性、简洁性和可维护性,能够提高工作效率;

假设在一个项目中有20个页面,每个页面都需要向服务器发送请求来完成数据的交互,突然有一个新增的需求,要给请求中的data里加一个参数,如果没有请求进行封装的话,这20个页面中每个请求都需要修改一次,非常的不方便,而封装之后只需要修改封装的js文件里的内容就好了;

而且在 VueCLI 创建的 Vue 项目中,如果不封装 axios 请求,一般需要把 axios 实例挂载在 Vue 实例的原型上;

而封装之后则可以哪里需要哪里引入,不必再挂载在原型上,降低了代码的耦合度,提高了安全性;

链接奉上

vue父子组件生命周期

挂载阶段
父beforeCreate -----> 父created -----> 父beforeMount ----> 子beforeCreate ----> 子created ---->
子beforeMount ----> 子mounted ----> 父mounted

更新阶段
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated

销毁阶段
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

规律就是:父组件肯定要等子组件加载完它才能完,所以开始阶段肯定是父组件先加载先开始执行,然后等到子组件执行完,父组件收尾。

早点睡,少熬夜,早睡早起身体好

猜你喜欢

转载自blog.csdn.net/ytfty24124/article/details/128010272
今日推荐