vue面试题

文章目录

1.v-show和v-if指令的共同点和不同点?

1) v-show与v-if的共同点:
我们都知道在 vue 中 v-show 与 v-if 的作用效果是相同的(不含v-else),都能控制元素在页面是否显示

在用法上也是相同的

<Model v-show="isShow" />
<Model v-if="isShow" />
  • 当表达式为true的时候,都会占据页面的位置
  • 当表达式都为false时,都不会占据页面位置

2)v-show与v-if的区别

  1. 控制手段不同
  2. 编译过程不同
  3. 编译条件不同

控制手段:v-show隐藏则是为该元素添加css–display:none,dom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除

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

编译条件:v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染

  • v-show 由false变为true的时候不会触发组件的生命周期

  • v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法

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

3)v-show与v-if的使用场景
v-if 与 v-show 都能控制dom元素在页面的显示

v-if 相比 v-show 开销更大的(直接操作dom节点增加与删除)

如果需要非常频繁地切换,则使用 v-show 较好

如果在运行时条件很少改变,则使用 v-if 较好

2.vue组件中data为什么是一个函数?

  1. vue中data必须是函数是为了保证组件的独立性和可复用性,data是一个函数,组件实例化的时候这个函数将会被调用,返回一个对象,计算机会给这个对象分配一个内存地址,你实例化几次,就分配几个内存地址,他们的地址都不一样,所以每个组件中的数据不会相互干扰,改变其中一个组件的状态,其它组件不变。

  2. 为了防止多个组件实例对象之间共用一个data,产生数据污染。采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象

3. $nextTick的使用

1)什么是$nextTick?
$nextTick是vue.js中的一个重要方法,他被称为"异步队列",他的功能是在当前代码执行完毕之后执行回调函数,实现响应式、异步更新。

SnextTick 的具体用法
1、更新 DOM
当 vue 实例中的数据发生变化时,使用SnextTick 可以实现立即更新 DOM。因为 Vue.js 将所有数据变化放入异步更新队列,所以在发生变化之后,如果要立即更新 DOM,就可以采用$nextTick 选项这样就可以实现响应式更新 DOM。

代码示例:
this.name = name
$nextTick(0 =>{
// DOM 更新完成
})

2、异步操作
在 Vue 实例中,如果需要执行一些异步操作,可以使用SnextTick方法,在当前代码执行完成之后执行。一般来说,只有在异步操作之后才能获取到期望的结果,因此在使用SnextTick 方法实现异步操作时,可以将回调函数放入SnextTick 中,以便及时获取期望结果。

代码示例:
$nextTick(0)=>[
axios.get(url).then(res => {
//取请求的结果
).catch(err =>[
//常处理
})
})

3、强制刷新组件
在 Vue.js 中,有时候你想要强制刷新组件,比如在某个接口请求完毕后想要立即刷新页面的组件,这时候就可以使用SnextTick 方法,它可以支持强制更新组件。

代码示例:
$nextTick(0) =>{
this.$forceUpdate()
})

总结
以上就是 Vue.js 中特殊方法$nextTick 及其具体用法的详细分析,它可以用于 Vue 实例中的 DOM 更新、异步操作、强制刷新组件等它可以在数据发生变化之后立即更新 DOM,也可以将回调函数放入SnextTick 中实现异步操作,甚至可以使用SnextTick 来强制刷新组件,从而获得期望的结果

4. vue中双向数据绑定是如何实现的?

什么是双向绑定?

我们先从单向绑定切入单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了View,Model的数据也自动被更新了

双向绑定的原理是什么?

我们都知道 Vue 是数据双向绑定的框架,双向绑定由三个重要部分构成

数据层(Model):应用的数据及业务逻辑
视图层(View):应用的展示效果,各类UI组件
业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来
而上面的这个分层的架构方案,可以用一个专业术语进行称呼:MVVM这里的控制层的核心功能便是 “数据双向绑定” 。自然,我们只需弄懂它是什么,便可以进一步了解数据绑定的原理

实现双向绑定

vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的,
也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随
之发生改变;
核心:关于 VUE 双向数据绑定,其核心是 Object.defineProperty()方法。

5.v-if和v-for的优先级?

  • 在vue2中,v-for的优先级高于v-if;
  • 在vue3中,v-if的优先级高于v-for。

在vue中,永远不要把v-if和v-for同时用在同一个元素上,会带来性能方面的浪费(每次渲染都会先循环再进行条件判断);想要避免出现这种情况,可在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环。

6.vue 常用的修饰符

vue中修饰符分为以下五种:

  • 表单修饰符
  • 事件修饰符
  • 鼠标按键修饰符
  • 键值修饰符
  • v-bind修饰符

应用场景:

.stop:阻止事件冒泡
.native:绑定原生事件
.once:事件只执行一次
.self :将事件绑定在自身身上,相当于阻止事件冒泡
.prevent:阻止默认事件
.caption:用于事件捕获
.once:只触发一次
.keyCode:监听特定键盘按下
.right:右键

7.vue自定义指令详解,以及应用场景?

vue2 和vue3 是不一样的
vue2:
全局自定义指令:vue.directive(’第一个参数是指令名称‘,{第二个参数是一个对象,这个对象有钩子函数})
局部自定义指令通过组件options选项中设置directive属性,是定义在组件内部的,只能在当前组件中使用
自定义指令应用场景:防抖 图片懒加载 一键copy的功能
自定义指令的钩子函数
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用
vue3:
created - 新增!在元素的 attribute 或事件监听器被应用之前调用。
bind 变为 → beforeMount 在元素被插入到 DOM 前调用,通常进行css的操作
inserted 变为→ mounted 可以进行DOM操作
beforeUpdate:新增!在元素本身被更新之前调用,与组件的生命周期钩子十分相似。
update → 移除!该钩子与 updated 有太多相似之处,因此它是多余的。请改用 updated。
componentUpdated → updated
beforeUnmount:新增!与组件的生命周期钩子类似,它将在元素被卸载之前调用。
unbind -> unmounted

8.vue 插槽 (slot)

1) 什么是插槽?
插槽(Slot)是 Vue 提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制
2)插槽的分类
插槽有三种:默认插槽、具名插槽、作用域插槽。

9.vue初始化页面闪动问题?

背景
使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。
解决方法
vue指令:v-cloak渲染指令(v-cloak 指令是解决屏幕闪动的好方法)
v-cloak要放在什么位置呢,是不是每个需要渲染数据的标签都要添加这个指令,经过试验发现,v-cloak并不需要添加到每个标签,只要在el挂载的标签上添加就可以,

方法一:

<p class="#app" v-cloak>
	<p>{{value.name}}</p>
</p>

而且,在css里面要添加

<style>
    [v-cloak] {
        display: none;
    }
</style>

方法二:(第一种没有彻底解决问题)
在根元素加上

style=“display: none;:style={display: block }

总结
v-cloak原理是先通过样式隐藏内容,然后在内存中进行值的替换,将替换的内容再反馈给界面,数据渲染完成之后,v-cloak 属性会被自动去除。

10. vue更新数组时触发视图更新的方法?

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

  1. 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue

  2. 当你修改数组的长度时,例如:vm.items.length = newLength

VUE给出了方法:vue.set() ,或者写成 this.$set(ARR)

调用方法:Vue.set( target, key, value )
target:要更改的数据源(可以是对象或者数组)

key:要更改的具体数据

value :重新赋的值

现在的代码就可以写成

Vue.set( this.items, 2, {message:"Change Test",id:'1'} )

页面视图也会更新。

还有 变异方法 (mutation method):

变异方法 ,顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异 (non-mutating method) 方法,例如:filter(), concat() 和 slice() 。这些不会改变原始数组,但总是返回一个新数组。

1. push()
2. pop()
3. shift()
4. unshift()
5. splice()
6. sort()
7. reverse()

11.Vue2.0 和 Vue3.0 有什么区别?

一、哪些变化?

概览Vue3的新特性,如下:

  • 速度更快
  • 体积减少
  • 更易维护
  • 更接近原生
  • 更易使用

速度更快

vue3相比vue2

  • 重写了虚拟Dom实现
  • 编译模板的优化
  • 更高效的组件初始化
  • undate性能提高1.3~2倍
  • SSR速度提高了2~3倍

1.体积更小

通过webpack的tree-shaking功能,可以将无用模块“剪辑”,仅打包需要的能够tree-shaking,有两大好处:

  1. 对开发人员,能够对vue实现更多其他的功能,而不必担忧整体体积过大

  2. 对使用者,打包出来的包体积变小了

vue可以开发出更多其他的功能,而不必担忧vue打包出来的整体体积过多

2.更易维护
可与现有的Options API一起使用
灵活的逻辑组合与复用
Vue3模块可以和其他框架搭配使用
2.1 更好的Typescript支持
2.2 编译器重写

3.更接近原生
可以自定义渲染 API
4. 更易使用
响应式 Api 暴露出来

二、Vue3新增特性

Vue 3 中需要关注的一些新功能包括:

  • framents
  • Teleport
  • composition Api
  • createRenderer

12.vue3带来了哪些好处?

1.性能的提升

  • 打包大小减少41%

  • 初次渲染快55%, 更新渲染快133%

  • 内存减少54%

2.源码的升级

  • 使用Proxy代替defineProperty实现响应式

  • 重写虚拟DOM的实现和Tree-Shaking

3.拥抱TypeScript

  • Vue3可以更好的支持TypeScript

4.新的特性

  1. Composition API(组合API)
    • setup配置
    • ref与reactive
    • watch与watchEffect
    • provide与inject
  2. 新的内置组件
    • Fragment
    • Teleport
    • Suspense
  3. 其他改变
    • 新的生命周期钩子
    • data 选项应始终被声明为一个函数
    • 移除keyCode支持作为 v-on 的修饰符

13.reactive与ref的区别?

我们都知道ref函数和reactive函数都是用来定义响应式数据;
但是reactive更适合定义复杂的数据类型(json/arr)、ref适合定义基本数据类型(可接收基本数据类型和对象)

reactive:

  1. 它的响应式是更加‘深层次’的,底层本质是将传入的数据包装成一个Proxy。

  2. 参数必须是对象或者数组,如果要让对象的某个元素实现响应式时比较麻烦。需要使用toRefs

ref:

  1. 函数参数可以是基本数据类型,也可以接受对象类型
  2. 如果参数是对象类型时,其实底层的本质还是reactive,系统会自动根据我们给ref传入的值转换成:
ref(1)->reactive({value:1})
ref函数只能操作浅层次的数据,把基本数据类型当作自己的属性值;
深层次依赖于reactive
  1. 在template中访问,系统会自动添加.value;在js中需要手动.value
  2. ref响应式原理是依赖于Object.defineProperty()的get()和set()的。

14.计算属性和watch以及methods的区别?

Methods
methods 中都是封装好的函数,无论是否有变化只要触发就会执行

适用场景:组件中功能的封装,逻辑处理

Computed
computed: 是 vue 独有的特性计算属性,可以对 data 中的依赖项再重新计算得到一个新值,应用到视图中,和 methods 本质区别是 computed 是可缓存的, 也就是说 computed 中的依赖项没有变化,则 computed 中的值就不会重新计算, 而 methods 中的函数是没有缓存的。

适用场景:假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于A 。如果没有缓存,我们将不可避免的多次执行某个函数

Watch
watch 是监听 data 和计算属性中的新旧变化

适用场景:当需要在数据变化时执行“异步”或“开销较大”的操作时,这个方式是最有用的

15.$route 和 $router 的区别?

  1. $ router是用来操作路由,$route是用来获取路由信息

  2. $router是VueRouter的一个实例,他包含了所有的路由,包括路由的跳转方法,钩子函数等,也包含一些子对象(例如history)

  3. $ route是一个跳转的路由对象(路由信息对象),每一个路由都会有一个$route对象,是一个局部的对象。

$ router的用法

//常规方法
this.$router.push("/login");
//使用对象的形式 不带参数
this.$router.push({ path:"/login" });
//使用对象的形式,参数为地址栏上的参数
this.$router.push({ path:"/login",query:{username:"jack"} }); 
使用对象的形式 ,参数为params 不会显示在地址栏
this.$router.push({ name:'user' , params: {id:123} });

$route的介绍

主要的属性有:
this.$route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如/home/ews
 
this.$route.params 对象,包含路由中的动态片段和全匹配片段的键值对,不会拼接到路由的url后面
 
this.$route.query 对象,包含路由中查询参数的键值对。会拼接到路由url后面
 
this.$route.router 路由规则所属的路由器
 
this.$route.name 当前路由的名字,如果没有使用具体路径,则名字为空

16.v-model的使用?

1.基本使用
v-model可以实现表单元素和数据的双向绑定
什么是双向绑定?
例如:< input type=“text” v-model=“message”>
message的数据改变,input输入框中的数据会随之变化
input输入框中的数据变化了,message的数据也会改变

v-model其实是一个语法糖,它背后的本质是两个操作

  1. v-bind绑定一个value属性
  2. v-on指令给当前元素绑定input事件

< input type=“text” :value=“message” @input = “message = $event.target.value”>
和 < input type=“text” v-model=“message”>等价

17.v-on可以监听多个方法吗?

在vue中v-on是提供的事件绑定机制,它是可以用来监听多个方法的,能够使用@替代v-on,
比如:“< input type=“text” :value=“name” @input=“onInput” @focus=“onFocus” @blur=“onBlur” />”,

而同一个事件就会报错 < a href=“javascript:;” @click=“methodsOne” @click=“methodsTwo”></ a>

18.vue中过滤器有什么作用及详解?

过滤器(filter)是输送介质管道上不可缺少的一种装置,大白话,就是把一些不必要的东西过滤掉,过滤器实质不改变原始数据,只是对数据进行加工处理后返回过滤后的数据再进行调用处理,我们也可以理解其为一个纯函数。

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。

Vue 允许你自定义过滤器,可被用于一些常见的文本格式化

ps: Vue3中已废弃filter,如果有使用过滤器的场景,可以使用 计算属性

19.EventBus注册在全局上时,路由切换时会重复触发事件,如何解决呢?

建议在created里注册,在beforeDestory移出

在组件内的beforeRouteLeave中移除事件监听

20.vuex有哪几种属性?

vuex是一个状态管理工具
1)

  1. State仓库,vuex使用单一状态树,每一个应用最好仅包含一个store实例,不建议直接修改state的值,最好是通过commit方法调用mutation任务进行修改,方便后期数据的追踪;
  2. Mutations,定义方法动态修改state中的数据,不建议包含逻辑业务处理,处理一些同步任务;
  3. Actions,定义方法执行异步任务一些复杂的逻辑代码,view层通过store.dispath分发Action任务;
  4. Getter,类似vue实例中的计算属性特点,用来过滤规范改造数据;
  5. Module,项目特别复杂的时候使用,每一个模块拥有自己的state, mutation,Action,getter,代码逻辑更加清晰;

2)
state => 基本数据(数据源存放地)
getters => 从基本数据派生出来的数据
mutations => 提交更改数据的方法,同步
actions => 像一个装饰器,包裹mutations,使之可以异步
modules => 模块化vuex

21.请详细说下你对vue生命周期的理解?

生命周期

每个Vue组件都有生命周期,过程为创建 -> 挂载 -> 更新 -> 销毁。开发者可以通过钩子函数(如mounted)在组件生命周期中的不同时刻进行操作。

在vue2 中:
  1. beforeCreate (创建前): 数据观测和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、 computed、watch、methods上的方法和数据。
  2. created (创建后) : 实例创建完成,实例上配置的 options 包括 data、 computed、watch、methods 等都配置完成,但是此时渲染得节点还未挂载到 DOM,所以不能访问到 $el 属性。
  3. beforeMount(挂载前): 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配3置: 编译模板,把data里面的数据和模板生成html。此时还没有挂载html到页面上。
  4. mounted (挂载后): 在el被新创建的 vm.sSel 替换,并挂载到实例上去之后调用。实例已完成以下的配置:4用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html染到html 页面中。此过程中进行ajax交互
  5. beforeUpdate (更新前): 响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM还没有被渲染。
  6. updated (更新后): 在由于数据更改导致的虚拟DOM重新染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多教情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
  7. beforeDestroy (销毁前): 实例销毁之前调用。这一步,实例仍然完全可用, this 仍能获取到实例。
  8. destroyed(销毁后): 实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监器会被移除,所有的了实例也会被销毁。该钩了在服务端渲染期间不被调用。

另外还有 keep-alive 独有的生命周期,分别为 activated 和 deactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 activated 钩子函数。

vue3中的声明周期

1、setup() : 开始创建组件之前,在 beforeCreate 和 created 之前执行,创建的是 data 和 method

2、onBeforeMount() : 组件挂载到节点上之前执行的函数;

3、onMounted() : 组件挂载完成后执行的函数;

4、onBeforeUpdate(): 组件更新之前执行的函数;

5、onUpdated(): 组件更新完成之后执行的函数;

6、onBeforeUnmount(): 组件卸载之前执行的函数;

7、onUnmounted(): 组件卸载完成后执行的函数;

8、onActivated(): 被包含在 中的组件,会多出两个生命周期钩子函数,被激活时执行;

9、onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;

10、onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。

二、Vue2.X和Vue3.X对比

vue2           ------->      vue3
 
beforeCreate   -------->      setup(()=>{})
created        -------->      setup(()=>{})
beforeMount    -------->      onBeforeMount(()=>{})
mounted        -------->      onMounted(()=>{})
beforeUpdate   -------->      onBeforeUpdate(()=>{})
updated        -------->      onUpdated(()=>{})
beforeDestroy  -------->      onBeforeUnmount(()=>{})
destroyed      -------->      onUnmounted(()=>{})
activated      -------->      onActivated(()=>{})
deactivated    -------->      onDeactivated(()=>{})
errorCaptured  -------->      onErrorCaptured(()=>{})

总结: Vue2和Vue3钩子变化不大,删除了beforeCreate 、created 两个钩子使用setup()钩子来替代。

22.vue优点?

1. 轻量级
Vue作为一款轻量级前端框架,大小只有18–21KB,工程搭建简单,只需要几行命令符。因为Vue使用的主体语言为JS,开发者可以灵活地将其他框架(如React和Angular)的项目迁移到Vue,具有很高的集成能力。Vue提供的router路由可以便捷地搭建一个多界面应用。

2. 高性能
虚拟DOM和响应式避免了不必要的全局重新渲染,提升了用户体验,使用户操作更加流畅。

3. 好上手
与面向对象编程性质类似,组件化更符合人类思维。打个比方,我们在设计网页时,通常会把一个界面分成一块一块的、用于某功能的特定样式模块。Vue的组件化使前端开发更加容易理解,同时MVVM可以更便捷地实现交互,对新手十分友好。

4. 插件化
由于Vue框架的流行性,目前有许多基于Vue的npm扩展包和开发工具(如Vuex)。Vue可以在一个文件下统一管理所有外部插件的全局使用。

5. 便于测试
组件化利于开发者对于单一组件进行测试,很少发生在整个页面下找不到是哪个地方报错的情况。

6.运行速度更快
像比较与react而言,同样都是操作虚拟dom,就性能而言,vue存在很大的优势

7.视图,数据,结构分离
使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作
8.虚拟dom

23.单页面应用和多页面应用区别及优缺点?

单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。

多页面(MPA),就是指一个应用中有多个页面,页面跳转时是整页刷新

单页面的优点:

  1. 用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小
  2. 前后端分离
  3. 页面效果会比较炫酷(比如切换页面内容时的专场动画)

单页面缺点:

  1. 不利于seo
  2. 导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理)
  3. 初次加载时耗时多
  4. 页面复杂度提高很多
  5. 容易造成css重名

多页面应用的优点

  1. 首屏加载快
  2. 利于SEO

24.vue路由跳转传参的方式有哪些?

  1. params传参(显示参数)
    在url中会显示出传参的值,刷新页面不会失去拿到的参数,使用该方式传值的时候,需要子路由提前配置好参数:
//路由参数配置
const router = new VueRouter({
  routes: [{
    path: '/about/:id',
    component: User
  }]
})
 
//声明式导航使用
<router-link to="/about/12">跳转</router-link>
//路由参数配置
const router = new VueRouter({
  routes: [{
    name: 'user1',
    path: '/about/:id',
    component: User
  }]
})
 
//声明式导航使用
<router-link :to="{ name: 'user1', params: { id: 123 } }">跳转</router-link>
  1. params传参(不显示参数)
    在url中不会显示出传参的值,但刷新页面会失去拿到的参数,使用该方式 传值 的时候,需要子路由提前配置好name参数:
//路由参数配置
const router = new VueRouter({
  routes: [{
    name: 'user1',
    path: '/about',
    component: User
  }]
})
 
//声明式导航使用
<router-link :to="{ name: 'user1', params: { id: 123 } }">跳转</router-link>
  1. query 传参
    query 传过去的参数会拼接在地址栏中(?name=xx),刷新页面数据不会丢失,使用path和name都可以:
//路由参数配置
const router = new VueRouter({
  routes: [{
    name: 'user1',
    path: '/about',
    component: User
  }]
})
 
//使用name
<router-link :to="{ name: 'user1', query: { id: 123 }}"></router-link>
//使用path
<router-link :to="{ path: '/about', query: { id: 123 } }"></router-link>

获取参数

  1. params的获取方式
this.$route.params.xxx
  1. query的获取方式
this.$route.query.xxx

需要注意的点
1、如果使用params传参,且参数是以对象的形式,跳转路径只能使用name形式而不能用path.

2、如果想要params参数想传参也可以不传参需要在占位符后面加?。

//路由参数配置
const router = new VueRouter({
  routes: [{
    path: '/search/:keyword?',
    name: 'search',
    component: () => import('@/pages/Search'),
    meta: { show: true }
  }]
})
//编程式传参
 this.$router.push({
    name: "search",
    params: {},
    query: { keyword: this.keyword },
 });

3、解决params传值为空字符串路径会出现问题:

 this.$router.push({
      name: "search",
      params: { keyword: "" || undefined },
      query: { keyword: this.keyword },
 });

25.vue遇到的坑,如何解决的?

vue1.0 升级2.0有很多坑:生命周期;路由中引入静态js,全局组件,全局变量,全局function;v-for循环的key,value值互换了位置,还有track-by;filter过滤器;遍历数组时,key值不能做model;父子通信等等

26.vue封装通用组件方法思路?

Vue 组件的封装思路,可以归结为几个步骤:
1、根据功能把需要实现的功能分成多个组件,每个组件间有不同的职责划分;
2、如果有需要,可以对组件进行通用化封装,将公共部分抽离出来,以减少重复代码,提高组件的复用性:
3、组件内部可以使用 props 传递参数,也可以使用events 传递事件,但是要注意不要滥用,以保证组件的职责划分清晰;
4、在 Vue 中,组件可以接收到 data 和 computed属性,这些属性可以定义组件的一些特征,比如颜色、宽度等,也可以使用 methods 来定义组件的交互行为;5、在 Vue 中,可以使用 watch 来监听 props 或者data 的变化,以实现组件内部逻辑的触发:
6、在组件封装的时候,要注意组件的生命周期,以便及时释放或者重新获取资源:
7、在实现组件的时候,要注意 DOM 结构的优化,以减少不必要的渲染次数,以提高组件的性能:
8、在封装组件的时候,需要考虑组件的通用性,可以尽量将组件的实现方式封装的更加灵活,以满足更多的业务场景;
9、在组件封装完成之后,可以进行单元测试,确保组件可以正常工作,并且能够提供可靠的服务;
10、最后,组件封装完成后,可以将组件发布到 NPM上,以便其他开发者可以使用,也可以提供参考和学习,以促进Vue的发展

总结起来,Vue 组件封装思路包括:根据功能把需要实现的功能分成多个组件:如果有需要,可以对组件进行通用化封装;使用 props 传递参数;使用 data 和computed 属性定义组件的特征;使用 watch 监听 props或 data 的变化:注意组件的生命周期:优化 DOM 结构:考虑组件的通用性:进行单元测试;将组件发布到 NPM上。以上这些步骤,是 Vue 组件封装思路的概括

27.Vue.js中ajax请求代码应该写在组件的methods中还是vuex的actions中?

  1. 如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。

  2. 如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。如果不要复用这个请求,那么直接写在vue文件里很方便。

28.Vuex中如何异步修改状态?

vuex有五个主要的属性,action getters mutations state module。

Action 类似于mutation,不同在于:
Action 提交的是mutation, 而不是直接变更状态;
Action 可以包含任意异步操作;
操作步骤:
(1)actions 里面放我们函数,函数里面的参数context ,可以帮我们提交的mutations。
逻辑梳理:到时候在组件内部,调用actions之后,actions里面又去调用mutations,而mutations又去修改了state。

29.刷新浏览器后,Vuex的数据是否存在?如何解决?

在vue项目中用vuex来做全局的状态管理, 发现当刷新网页后,保存在vuex实例store里的数据会丢失。

原因:因为 store 里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值初始化。

我们有两种方法解决该问题:

  1. 使用 vuex-along
  2. 使用 localStorage 或者 sessionStroage

使用vuex-along
vuex-along 的实质也是将 vuex 中的数据存放到 localStorage 或者 sessionStroage 中,只不过这个存取过程组件会帮我们完成,我们只需要用vuex的读取数据方式操作就可以了,简单介绍一下 vuex-along 的使用方法。

安装 vuex-along:

npm install vuex-along --save

配置 vuex-along: 在 store/index.js 中最后添加以下代码:

import VueXAlong from 'vuex-along' //导入插件
export default new Vuex.Store({
    //modules: {
        //controler  //模块化vuex
    //},
    plugins: [VueXAlong({
        name: 'store',     //存放在localStroage或者sessionStroage 中的名字
        local: false,      //是否存放在local中  false 不存放 如果存放按照下面session的配置
        session: { list: [], isFilter: true } //如果值不为false 那么可以传递对象 其中 当isFilter设置为true时, list 数组中的值就会被过滤调,这些值不会存放在seesion或者local中
    })]
});

使用 localStorage 或者 sessionStroage

created() {
    //在页面加载时读取sessionStorage里的状态信息
    if (sessionStorage.getItem("store")) {
      this.$store.replaceState(
        Object.assign(
          {},
          this.$store.state,
          JSON.parse(sessionStorage.getItem("store"))
        )
      );
    }
    //在页面刷新时将vuex里的信息保存到sessionStorage里
    window.addEventListener("beforeunload", () => {
      sessionStorage.setItem("store", JSON.stringify(this.$store.state));
    });
},

30.vuex中的辅助函数怎么使用?

1. mapState

import { mapState } from 'vuex'
 
export default {
  // ...
  computed:{
     ...mapState({
         // 箭头函数可使代码更简练
         count: state => state.count,
         // 传字符串参数 'count' 等同于 `state => state.count`
         countAlias: 'count',
 
         // 为了能够使用 `this` 获取局部状态,必须使用常规函数
         countPlusLocalState (state) {
             return state.count + this.localCount
         }
  	})
  }
}

定义的属性名与state中的名称相同时,可以传入一个数组:

//定义state
const state={
    count:1,
}
 
//在组件中使用辅助函数
computed:{
    ...mapState(['count'])
}

2. mapGetters

computed:{
    ...mapGetters({
      // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
      doneCount: 'doneTodosCount'
    })
}

当属性名与getters中定义的相同时,可以传入一个数组

总结:

  • mapState与mapGetters都用computed来进行映射
  • 在组件中映射完成后,通过this.映射属性名进行使用

3. mapMutations

methods:{
    ...mapMutations({
        add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
}

当属性名与mapMutatios中定义的相同时,可以传入一个数组

methods:{
    ...mapMutations([
        'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
 
        // `mapMutations` 也支持载荷:
        'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
}

** 4. mapActios**

mathods:{
    ...mapActions({
        add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
}

当属性名与mapActios中定义的相同时,可以传入一个数组

methods:{
    ...mapActions([
        'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`	
        // `mapActions` 也支持载荷:
        'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
}

总结

  • mapMutations与mapActios都在methods中进行映射
  • 映射之后变成一个方法
    ** 5. 多个modules**
  • 在不使用辅助函数的时候,
this.$store.commit('app/addCount')
  • 使用辅助函数,辅助函数的第一个参数给定命名空间的路径
computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo', // -> this.foo()
    'bar' // -> this.bar()
  ])
}

或者使用 createNamespacedHelpers函数来创建一个基于命名空间的辅助函数

import { createNamespacedHelpers } from 'vuex'
 
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module') //给定路径
//使用方法与之前相同
export default {
  computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // 在 `some/nested/module` 中查找
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}

31.vue插槽的理解?

声明自己对于插槽的理解:其实就是一种父子组件传值的一种方式。

需要明白两点:

  1. 插槽是使用在子组件中的。
  2. 插槽是为了将父组件中的子组件模板数据正常显示

1、vue2.0的插槽

匿名插槽

<div id="app">
    <div class="father">
        <h3>这里是父组件</h3>
        <child>
           <span>我是插槽插入的内容</span>
        </child>
    </div>
</div>
<template id="child">
    <div class="child">
        <h3>这里是子组件</h3>
        <slot></slot>
    </div>
</template>
<script>
    var vm = new Vue({
        el: '#app',
        data: {},
        components: {
            child: {
                template: '#child'
            }
        }
 
    });
 
</script>

上面的代码所展示的效果就是你会发现在

这里是子组件

会多一行 我是插槽插入的内容
如果你在子组件里面不写 的话你会发现你无论在父组件里面写多少标签都不会被渲染到子标签中。

具名插槽

<div id="app">
    <div class="father">
        <h3>这里是父组件</h3>
        <child>
            <span slot="demo1">菜单1</span>
            <span>菜单2</span>
            <span slot="demo3">菜单3</span>
        </child>
    </div>
</div>
<template id="child">
    <div class="child">
        <h3>这里是子组件</h3>
        <slot></slot>
        <slot name="demo3"><slot>
    </div>
</template>
<script>
    var vm = new Vue({
        el: '#app',
        data: {},
        components: {
            child: {
                template: '#child'
            }
        }
    });
</script>

具名插槽其实就是在父组件中添加一个 slot=‘自定义名字’ 的属性,然后在子组件中的 里面添加 <name=‘自定义名字’ 即可,如果父组件中有一部分没有添加 slot 属性,则此处就是默认的插槽,在子组件中的 直接就是使用的父组件的默认插槽部分!

作用域插槽
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。不过,我们可以在父组件中使用slot-scope 特性从子组件获取数据,前提是需要在子组件中使用:data=data 先传递data 的数据!

<div id="app">
    <div class="father">
        <h3>这里是父组件</h3>
        <child>
            <div slot-scope="user">
                {{user.data}}
            </div>
        </child>
    </div>
</div>
<script>
    Vue.component('child', {
        template:'' +
            '<div class="child">\n' +
            '    <h3>这里是子组件</h3>\n' +
            '    <slot  :data="data"></slot>\n' +
            '  </div>',
        data: function () {
            return {
                data: ['zhangsan', 'lisi', 'wanwu', 'zhaoliu', 'tianqi', 'xiaoba']
            }
        }
    });
    var vm = new Vue({
        el: '#app',
    });
</script>

页面显示的结果如下:

这里是父组件

这里是子组件

[‘zhangsan’, ‘lisi’, ‘wanwu’, ‘zhaoliu’, ‘tianqi’, ‘xiaoba’]

2、vue3.0中插槽的使用

匿名插槽用法不变
下面我们来看一下具名插槽的写法!

// 子组件
<div class="hello">
    我是一个封装的组件
     <slot name="num"></slot>
  </div>
  
  
// 父组件
<HelloWorld v-model="masg" v-slot:num>
    <div>我是插槽插入的</div>
</HelloWorld>
 
// 父组件的另外一个写法
<HelloWorld v-model="masg">
    <template v-slot:num>
         <div>我是插槽插入的</div>
    </template>
</HelloWorld>

Vue3(其实从2.6开始)中引入了一个新的指令 v-slot,用来表示具名插槽和默认插槽。
在 v2.5 之后屏蔽了 slot-scope,
v-slot引入使其插槽更接近指令化。
作用域插槽的用法

// 子组件
<div class="hello">
    我是一个封装的组件
     <slot :num="num"></slot>
</div>
 
<script>
import { ref } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
    // msg: String,
    modelValue: String
  },
 setup(prop,context){
   const num = ref(10);
   return { num }
 }
}
</script>
 
// 父组件
<HelloWorld>
  <template v-slot="{num}">
     <div>{{num}}</div>
  </template>
</HelloWorld>
 
// 也可以改成下面的写法
<HelloWorld v-slot="{num}">
   <div>{{num}}</div>
</HelloWorld>
 
和 v-bind和v-on相似,缩写只有在存在参数时才生效,这就意味着v-slot没有参数时不能使用#=,对于默认插槽,可以使用#default来代替v-slot
 
 
// 上面我们写过具名插槽可以这么写
 
<HelloWorld v-model="masg">
    <template #num>
         <div>我是插槽插入的</div>
    </template>
</HelloWorld>
 
// 或者如上面的作用域插槽也可以改成下面的写法
 
<HelloWorld>
  <template #default="{num}">
     <div>{{num}}</div>
  </template>
</HelloWorld>

32.vue3中如何获取refs,dom对象的方式?

  1. ref.value获取到的是null
    答:检查是否将ref变量return出去了
    答:检查是在哪里进行的console.log,setup函数相当于vue2中的
    beforeCreate, created阶段,如果直接在setup中直接使用console.log获取ref,返回的自然是null

  2. ref.value获取到的数据怎么使用
    答:在函数、生命周期里,例: myRef.value.className

  3. 获取多个dom,push重复数据
    答:检查setup函数执行了几次

可以将文章中的示例代码完完整整的拷贝到新项目的app.vue中,运行后可直接查看效果。

Vue 2.x获取DOM

<div ref="myRef"></div>

this.$refs.myRef

Vue 3.0获取单个DOM

<template>
  <div ref="myRef">获取单个DOM元素</div>
</template>

<script>
import { ref, onMounted } from 'vue';

export default {
  setup() {
    const myRef = ref(null);

    onMounted(() => {
      console.dir(myRef.value);
    });
 
    return {
      myRef
    };
  }
};
</script>

Vue 3.0获取多个DOM(一般用于获取数组)

<template>
  <div>获取多个DOM元素</div>
  <ul>
    <li v-for="(item, index) in arr" :key="index" :ref="setRef">
      {{ item }}
    </li>
  </ul>
</template>

<script>
import { ref, nextTick } from 'vue';

export default {
  setup() {
    const arr = ref([1, 2, 3]);

    // 存储dom数组
    const myRef = ref([]);

    const setRef = (el) => {
      myRef.value.push(el);
    };

    nextTick(() => {
      console.dir(myRef.value);
    });

    return {
      arr,
      setRef
    };
  }
};
</script>

注:console.dir()可以显示一个对象所有的属性和方法
效果图
在这里插入图片描述

33.vue3中生命周期的和vue2中的区别?

Vue2.X和Vue3.X对比
vue2 -------> vue3

beforeCreate --------> setup(()=>{})
created --------> setup(()=>{})
beforeMount --------> onBeforeMount(()=>{})
mounted --------> onMounted(()=>{})
beforeUpdate --------> onBeforeUpdate(()=>{})
updated --------> onUpdated(()=>{})
beforeDestroy --------> onBeforeUnmount(()=>{})
destroyed --------> onUnmounted(()=>{})
activated --------> onActivated(()=>{})
deactivated --------> onDeactivated(()=>{})
errorCaptured --------> onErrorCaptured(()=>{})

34.说说vue中的diff算法?

diff整体策略为:深度优先,同层比较

  1. 比较只会在同层级进行,不会跨层级比较
  2. 比较的过程中,循环从两边向中间收拢

在新老虚拟DOM对比时

  • 首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换
  • 如果为相同节点,进行patchVnode,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)
  • 比较如果都有子节点,则进行updateChildren,判断如何对这些新老节点的子节点进行操作(diff核心)。 匹配时,找到相同的子节点,递归比较子节点

在diff中,只对同层的子节点进行比较,放弃跨级的节点比较,使得时间复杂从O(n^3)降低值O(n),也就是说,只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较。

35.说说 Vue 中 CSS scoped 的原理?

  1. 增加了scoped属性之后,就会在当前这个组建的节点上增加一个data-v-xxx属性
  2. 此组件所用的css,都会被设置为属性选择器
  3. 通过css的属性选择器从而解决了多个组件重复的class,会导致冲突的问题

36.vue3中怎么设置全局变量?

方式1、
可以设置一个专用的的全局变量模块文件,模块里面定义一些变量初始状态,用export default 暴露出去,在main.js里面使用Vue.prototype挂载到vue实例上面或者在其它地方需要使用时,引入该模块这样就达到了修改全局变量的目的了。

方式2、

  • main.js设置全局变量
import api from '@/api'

app.config.globalProperties.$api = api
  • 使用全局变量,使用 getCurrentInstance 方法。
// ctx.$api 就是全局设置的变量
const {
  proxy: { $api },
} = getCurrentInstance();

// ctx.$api 就是全局设置的变量
const { ctx } = getCurrentInstance()

37.Vue 中给对象添加新属性时,界面不刷新怎么办?

vue2

  • 如果为对象添加少量的新属性,可以直接采用Vue.set()
  • 如果需要为新对象添加大量的新属性,则通过Object.assign()创建新对象
  • 可采取$forceUpdate()进行强制刷新 (不建议)

vue3是用过proxy实现数据响应式的,他不会出现这种情况,直接动态添加新属性仍可以实现数据响应式

38.谈谈对Vue中双向绑定的理解?

什么是双向绑定
就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了View,Model的数据也自动被更新了
双向绑定的原理是什么

我们都知道 Vue 是数据双向绑定的框架,双向绑定由三个重要部分构成

  • 数据层(Model):应用的数据及业务逻辑
  • 视图层(View):应用的展示效果,各类UI组件
  • 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来

理解ViewModel
它的主要职责就是:

  • 数据变化后更新视图
  • 视图变化后更新数据

当然,它还有两个主要部分组成

  • 监听器(Observer):对所有数据的属性进行监听
  • 解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

实现双向绑定(流程)

  1. new Vue()首先执行初始化,对data执行响应化处理,这个过程发生Observe中
  2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compile中
  3. 同时定义⼀个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数
  4. 由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家Dep来管理多个Watcher
    5.将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数

39.为什么vue2和vue3语法不可以混用?

数据也不通,谁在后面谁优先: setup 和 data
setup里没有this指向
vue2使用的是webpack形式去构建项目,而vue3使用vite构建项目。vue2中可以使用pototype的形式去进行操作,引入的是构造函数,vue3中需要使用结构的形式进行操作,引入的是工厂函数。

40.vue3中setup函数如何进行组件通讯?

1、父传子 ----defineProps

父组件:

<template>
  <children :list="list"></children>
  <div>
    <input v-model="value" type="text" placeholder="请输入" />
    <button @click="handleAdd"> 添加 </button>
  </div>
</template>
<script setup>
  import { ref } from 'vue'
  import Children from '@/views/parentChildCommunicat/parentToChildren/components/children.vue'

  const list = ref(['JavaScript', 'HTML', 'CSS'])
  const value = ref('')

  const handleAdd = () => {
    list.value.push(value.value)
    value.value = ''
  }
</script>

子组件:

<template>
  <ul>
    <li v-for="item in props.list" :key="item">{{ item }}</li>
  </ul>
</template>
<script setup>
  import { defineProps } from 'vue'

  const props = defineProps({
    list: {
      type: Array,
      default: () => []
    }
  })
</script>

2、子传父—defineEmits

子组件:

<template>
  <div>
    <input v-model="value" type="text" placeholder="请输入" />
    <button @click="handleAdd"> 添加 </button>
  </div>
</template>
<script setup>
  import { ref, defineEmits } from 'vue'

  const value = ref('')
  const emits = defineEmits(['add'])

  const handleAdd = () => {
    emits('add', value.value)
    value.value = ''
  }
</script>

父组件:

<template>
  <ul>
    <li v-for="item in list" :key="item">{{ item }}</li>
  </ul>
  <son @add="add" />
</template>
<script setup>
  import { ref } from 'vue'
  import Son from './components/son.vue'

  const list = ref(['JavaScript', 'HTML', 'CSS'])

  const add = (value) => {
    list.value.push(value)
  }
</script>

3、跨级组件通信

refs 实现组件间的通信(可跨级)—— defineExpose

41.vue3,Composition API 的优势?

Options API 存在的问题

  • OptionsAPI翻译过来就是配置式API, 也就是说我们的写 data配置、methods配置、computed配置、都是基于配置的! 也就意味着所有功能组成部分都拆散了! 当组件的功能多了,组件就不好维护了!
  • 使用传统OptionsAPI中,新增或者修改一个需求 ,需要分别在data,methods,computed里不断的修改 。(理想的状态就是将功拆解分开,一个data、methods、computed中对应一个功能点去使用)。

Composition API 的优势
1、Composition API就解决了 Options API 存在的问题!
2、功能比较发杂的组件,vue3中还可以自定义 hooks, 将单个功能封装成单个的函数,在集成到组件中去复用! 将功能进行解耦,方便维护、复用、可读性强!
3、想让Composition API 发挥出自己的威力! 需得借助hook函数!
4、hook就是把所有得方法、函数、计算属性、监听属性、数据、生命周期按照功能点进行打包, 打出来的包就是一个 hook函数!
5、更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。

42.shallowReactive和shallowRef的区别?

shallowReactive:只处理对象最外层属性的响应式(浅响应式)。
shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。

43.provide与inject如何使用?

provide与inject是Vue中用于跨组件通信的一对API,可以将数据或方法注入到子组件中。

provide用于在父组件中声明要提供给子组件使用的数据或方法,inject用于在子组件中注入父组件提供的数据或方法。

具体使用方法如下:

在父组件中使用provide声明要提供给子组件使用的数据或方法,如:

provide() {
  return {
    name: 'Vue',
    handleClick: this.handleClick
  }
},
methods: {
  handleClick() {
    console.log('Hello Vue!')
  }
}

在子组件中使用inject注入父组件提供的数据或方法,如:

inject: ['name', 'handleClick'],
mounted() {
  console.log(this.name) // 输出 'Vue'
  this.handleClick() // 输出 'Hello Vue!'
}

需要注意的是,provide和inject的数据或方法是单向下传递的,即只能由父组件提供给子组件使用,无法在子组件中修改父组件的数据或方法。同时,provide和inject的使用应该谨慎,不要滥用,以免造成代码复杂性和维护困难度的增加。

44.toRaw 与 markRaw是什么作用?

  • toRaw将代理对象变成普通对象,数据发生变化,不会更新
  • markRaw标记的对象数据,从此以后再也不能成为代理对象了

两者区别:toRaw会将整个对象变成非响应式的,markRaw可以指定哪些属性值可以变化,

<template>
    <div>
        <p>姓名:{{ person.name }}</p>
        <p>年龄:{{ person.age }}</p>
        <p>爱好:{{ person.like }}</p>
        <button @click="changemR">点我markerRaw 标记一个对象,使其永远不会再成为响应式对象</button>
        <br>
        <button @click="updateToRaw">测试toRaw 将一个由reactive生成的响应式对象 转为普通对象</button>
    </div>
</template>

<script setup>
import { reactive, markRaw, toRaw } from 'vue'
const person = reactive({
    name: '露丝',
    age: 20
})
let likes = ['js', 'css', 'vue']
person.like = markRaw(likes)
const changemR = () => {
    person.like[0] = '我爱学习' //变了,但是不是响应式的,打印出来有变化,但是页面没有渲染
    console.log(person.like);
}

// toraw
const updateToRaw = () => {
    const user = toRaw(person)
    user.name = '我是tworaw 之后的名字'
    console.log(user, 'user')

}

</script>

在这里插入图片描述

45.readonly 与 shallowReadonly谈谈你对他的理解?

  • readonly: 让一个响应式数据变为只读的(深只读)。
  • shallowReadonly:让一个响应式数据变为只读的(浅只读)。
  • 应用场景: 不希望数据被修改时。
    readonly与shallowReadonly都是让响应式数据只具备读的能力,后者是浅层次的只读,也就是只对数据对象第一层起作用,深层次的嵌套,当使用shallowReadonly()处理时,深层次数据支持被修改

在不希望数据被修改,或当数据是从别的地方取过来,不希望影响源数据时,使用readonly()或shallowReadonly()就很有用

46.自定义hook是什么?

hook,本质是一个函数。自定义hook,就是将setup中使用过的组合式函数进行封装,实现代码复用。类似于v2中的mixin

自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

  • 注意1:hook函数可以使用Vue3中的组合式API;
  • 注意2:hook函数在组件中使用时,相当于函数中的API方法都移动到相关组件中

47.虚拟DOM一定更快吗?

不一定,
原因:虚拟DOM渲染是将真实DOM转为js对象,然后将js对象转换为真实DOM,也就是是说他始终会创建DOM对象。在vue应用初次加载时,需要优先创建所有的虚拟DOM,然后在把虚拟DOM全部转换为真实DOM,消耗的时间一定会比直接渲染真实DOM更多的。

48.vue路由中,history和hash两种模式有什么区别?

最直观的区别就是在url中,hash带了#,history没有#,它们两个是路由配置mode的两个选项。

前端路由的核心是在改变视图的同时不会向后端发出请求,浏览器提供的这两种支持就是为了达到这一目的。

两种方式的对比
1、hash模式:

  • hash方式是指url中存在 # 的一种方式,是vueRouter的默认模式,
  • 当#后面的url地址发生变化时,浏览器不会向服务器发送请求,故不会刷新页面
  • 当#后面的url地址发生变化时,会触发hashChange(hash模式得核心实现原理)事件,从而,我们可以通过监听hashChange事件来知道路由发生变化,从而进一步去更新我们的页面
  • 只可修改hash部分
  • 当浏览器刷新时,浏览器只会向服务器去请求# 前面的域名服务器下根目录下的index.html文件
  • hash模式会创建hashHistory对象,hashHistory对象有两个方法,push() 和 replace()
    HashHistory.push()会将新的路由添加到浏览器访问的历史的栈顶,而HasHistory.replace()会替换到当前栈顶的路由

2、history模式:

  • history模式得路由和域名之间直接通过/连接,无#符分隔,就是普通url形式
  • history模式当发生路由跳转时,通过HTML5的history.pushState()方法或者history.replaceState() 方法改变地址栏地址,并将地址的改变记录到浏览器访问栈中。
  • 当浏览器前进,后退,或者调用back(),forward(), go()等方法时,会触发popstate事件。故,我们可以通过监听popstate事件来获取最新的路由地址,从而更新页面
  • 通过pushstate() 修改的url可以是与当前url同源的任意url。
  • 需要和服务器配合使用,否则容易出现页面404的情况

49.请谈谈wxml与标准的html的异同?

1.标签名称不同

HTML(div,span,img,a)
WXML(2view,text,image,navigator)

2.属性节点不同

HTML : < a href=“#”>超链接< /a>
WXML :< navigator url=“/pages/home/home”>< /navigator>

3.WXML中提供了类似于Vue中的模板语法

  • 数据绑定
  • 列表渲染
  • 条件渲染
    WXML可以通过上述模板语法快速实现一些功能

50.请谈谈WXSS和CSS的异同?

  1. WXSS增加了rpx尺寸单位,在不同大小的尺寸屏幕下会进行自动换算

  2. WXSS提供了全局样式(app.wxss)来对设置全局样式,和页面css来设置局部样式

  3. wxss只会支持css的部分选择器(.class/#id/element/并集后代后代选择器/等)

51.请谈谈微信小程序主要目录和文件的作用?

  • App.js:设置一些全局的基础数据,写入全局的公共方法;
  • App.json:路由和小程序全局配置项,底部tab,标题栏设置;
  • App.wxss:公共样式,引入iconfont;
  • pages文件夹:里面包含小程序里的页面;
  • index.json:配置当前页面的页面配置,例如标题,和引入组件;
  • index.wxml:页面结构;
  • index.wxss:页面样式表;
  • index.js:页面逻辑,请求和数据处理;

52.请谈谈小程序的双向绑定和vue的异同?

小程序中的数据双向绑定

  • 首先通过 bindinput 绑定文本框的输入事件
  • 在 data 中声明一个变量 content ,将其动态绑定成文本框的 value 值
  • 在 bindinput 事件中通过事件参数 e.detail.value 可以获取到文本框中最新的 value 值
  • 通过 this.setData 将文本框最新的 value 值 赋值给 动态绑定的value值 content 即可实现数据的双向绑定

vue中的数据双向绑定

  • 首先为文本框绑定 @input 监听文本框的输入事件
  • 为文本框动态绑定 value 属性,其值是在data中定义的变量
  • 在 @input绑定的事件中 通过事件参数 event.target.value 可以获取到 input 框中最新的value值
  • 将其重新获取到的 value 赋值给 value值动态绑定的那个变量

区别:

大体上区别不大,绑定事件不同,以及获取value值的具体方式不同,以及在小程序中设置data中的数据,需要调用 this.setData方法进行设置

53.简单描述下微信小程序的相关文件类型?

微信小程序项目结构主要有四个文件类型:

  1. WXML(weixin Markup Language) 是框架设计的一套标签语言,结合基础组件,事件系统,可以构建出页面的结构。内容主要事微信自己定义的一套组件。
  2. WXSS(WeiXin Style Sheets) 是一套样式语言,主要用于描述 WXML 的组件样式。
  3. JS 逻辑处理,网络请求
  4. json 小程序设置,静态配置
    主要文件

app.json 必须要有这个文件,此文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置tabBar 最少两个。

{
  "pages": [
    "pages/index/index",
    "pages/logs/logs",
    "pages/my/index"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#000000",
    "navigationBarTitleText": "我是微信小程序", //头部
    "navigationBarTextStyle": "white"
  },
  "tabBar": {
    "color": "#333",
    "selectedColor": "#FFA500", //选中后的颜色
    "list": [
      {
        "pagePath": "pages/index/index", //路径
        "text": "首页", //导航栏标签
        "iconPath": "static/baihome.jpg", //未选择的背景图
        "selectedIconPath": "static/heihome.jpg" //选中后的背景图
      },
      {
        "pagePath": "pages/logs/logs",
        "text": "日志",
        "iconPath": "static/rizhiwei.jpg",
        "selectedIconPath": "static/rizhidianji.jpg"
      },
      {
        "pagePath": "pages/my/index",
        "text": "我的",
        "iconPath": "static/mywei.jpg",
        "selectedIconPath": "static/mydianji.jpg"
      }
    ]
  },

  "style": "v2",
  "sitemapLocation": "sitemap.json"
}

54.微信小程序有哪些传值(传递数据)方法?

微信小程序的物种传值方式

55.bindtap和catchtap的区别?

bindtap和catchtap都是微信小程序中用来绑定事件的,但是它们有一些区别。

bindtap是绑定点击事件,当用户点击元素时触发。
catchtap是绑定捕获事件,当用户点击元素时触发,但是它会先于冒泡事件被触发,这可以用来阻止冒泡事件的触发。

所以区别就是,bindtap是冒泡事件,catchtap是捕获事件。

56.简述wx.navigateTo(),wx.redirectTo(),wx.switchTab(),wx.navigateBack(),wx.reLaunch()的区别?

wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面,使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不能跳转 tabbar 页面
wx.switchTab():跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
wx.navigateBack():关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层
wx.reLaunch():关闭所有页面,打开到应用内的某个页面

57.微信小程序与H5的区别?

简单来说,小程序是一种应用,运行的环境是微信(App);H5是一种技术,依附的外壳是是浏览器。

从「前端开发」的视角来看,微信小程序和H5也存在着多方面的不同。概括来说有以下四个方面的区别。

一、运行环境的不同

H5的运行环境是浏览器,包括webview,而微信小程序的运行环境并非完整的浏览器,因为小程序的开发过程中只用到一部分H5技术。

小程序的运行环境是微信开发团队基于浏览器内核完全重构的一个内置解析器,针对性做了优化,配合自己定义的开发语言标准,提升了小程序的性能。

二、开发成本的不同

开发一个微信小程序,由于微信团队提供了开发者工具,并且规范了开发标准,则简单得多。前端常见的HTML、CSS变成了微信自定义的WXML、WXSS,WXML,官方文档中都有明确的使用介绍,开发者按照说明专注写程序就可以了。

需要调用后端接口时,调用发起请求API;需要上传下载时,调用上传下载API;需要数据缓存时,调用本地存储API;引入地图、使用罗盘、调用支付、调用扫码等等功能都可以直接使用;UI库方面,框架带有自家weui库加成。

并且在使用这些API时,不用考虑浏览器兼容性,不用担心出现BUG,显而易见微信小程序的开发成本相对低很多

三、获取系统级权限的不同

微信小程序相对于H5能获得更多的系统权限,比如网络通信状态、数据缓存能力等,这些系统级权限都可以和微信小程序无缝衔接。

而这一点恰巧是H5 被诟病的地方,这也是H5的大多应用场景被定位在业务逻辑简单、功能单一的原因。

四、页面体验不同

H5网页需要在浏览器中渲染,会给人明显的「卡顿」感觉,面对复杂的业务逻辑或者丰富的页面交互时尤为明显。

而微信小程序,它的代码直接在微信上运行,省去了通过浏览器渲染的步骤,因此,在微信中使用小程序,才会比H5流畅很多。

除了首次打开需要几秒的加载时间外,小程序各个页面的切换、跳转等体验已经媲美原生App,有着同样的柔丝般顺滑的效果。

58.小程序和Vue写法的区别?

一、生命周期函数不一样:

  • 微信小程序为onLoad:页面加载,onShow:页面显示,onReady:页面初次渲染完成,onHide:页面隐藏,onUnload:页面卸载。
  • Vue的钩子函数在跳转新页面时,钩子函数都会触发,但是小程序的钩子函数,页面不同的跳转方式,触发的钩子并不一样。beforecreate、created适合做网络请求、beforemout更新data、mouted、beforeupdate、updated、beforedestory、destroyed。

二、数据请求时间不一样:
在页面加载请求数据时,两者钩子的使用有些类似,vue一般会在 created或者 mounted中请求数据,而在小程序,会在 onLoad或者 onShow中请求数据。

三、数据绑定方式不一样:
vue动态绑定一个变量的值为元素的某个属性的时候,会在变量前面加上冒号。小程序:绑定某个变量的值为元素属性时,会用两个大括号括起来,如果不加括号,为被认为是字符串。

四、 显示与隐藏元素不一样:
vue中,使用 v-if 和 v-show控制元素的显示和隐藏。小程序中,使用 wx-if和 hidden控制元素的显示和隐藏。

五、事件处理不一样:
vue:使用 v-on:event绑定事件,或者使用 @event绑定事件;小程序中,全用 bindtap=“”,或者 catchtap=‘’绑定事件,catchtap阻止事件冒泡。

六、数据双向绑定不一样:
在vue中,只需要在表单元素上加上 v-model,然后再绑定 data中对应的一个值,当表单元素内容发生变化时, data中对应的值也会相应改变。在小程序中,当表单内容发生变化时,会触发表单元素上绑定的方法,然后在该方法中,通过 this.setData({key:value})来将表单上的值赋值给 data中的对应值。

七、绑定事件传参不一样:
在vue中,绑定事件传参只需要在触发事件的方法中,把需要传递的数据作为形参传入。在小程序中,不能直接在绑定事件的方法中传入参数,需要将参数作为属性值,绑定到元素上的 data-属性上,然后在方法中通过 e.currentTarget.dataset.*的方式获取,从而完成参数的传递。

八、父子组件通信不一样:

  • ①子组件创建不一样:

在vue中需要:
1、编写子组件;
2、在需要使用的父组件中通过 import引入;
3、在 vue的 components中注册;
4、在模板中使用。

在小程序中需要:
1、编写子组件
2、在子组件的 json文件中,将该文件声明为组件;
3、在需要引入的父组件的 json文件中,在 usingComponents填写引入组件的组件名以及路径;
4、在父组件中,直接引入即可;

  • ②父子组件传值不一样:

在vue中,
父组件向子组件传递数据,只需要在子组件通过 v-bind传入一个值,在子组件中,通过 props接收,即可完成数据的传递,子组件和父组件通信可以通过 this.emit将方法和数据传递给父组件。

在小程序中,
父组件直接将值赋值给一个变量,在子组件 properties中,接收传递的值。

  • ③如果父组件想要调用子组件的方法

vue会给子组件添加一个 ref属性,通过 this.refs.ref的值便可以获取到该子组件,然后便可以调用子组件中的任意方法。
小程序是给子组件添加 id或者 class,然后通过 this.selectComponent找到子组件,然后再调用子组件的方法。

59.rpx的理解?

rpx(responsive pixel): 响应单位,可以根据屏幕宽度进行自适应。

  • rpx是微信小程序独有的、解决屏幕自适应的尺寸单位
  • 可以根据屏幕宽度进行自适应,不论大小屏幕,规定屏幕宽为750rpx
  • 通过 rpx 设置元素和字体的大小,小程序在不同尺寸的屏幕下,可以实现自动适配

60.微信小程序可以进行dom操作吗?

小程序不能使用各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作

原因:在小程序中,渲染层和逻辑层是分开的,分别运行在不同的线程中,逻辑层运行在 JS引擎中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。
为什么要这样设计?
因为JavaScript是可操纵DOM的,如果JavaScript线程和UI线程同时运行,即在修改这些元素属性同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致,导致传统web开发渲染线程和脚本线程是互斥的。于是当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到引擎线程空闲时立即被执行。 因此长时间的脚本运行可能会导致页面失去响应。

61.微信小程序自定义tabbar的理解?

微信小程序现有的在app.json中配置tabbar以及相应的api无法实现tabbar的动态切换,因此需要采用自定义tabbar的方式实现tabbar的动态切换。
一、微信小程序自定义tabbar配置

  1. 在app.json中配置tabbar相关信息,并指定custom字段为true;
  2. 所有 tab 页的 json 里需声明usingComponents项,也可以在app.json全局开启;
  3. 项目根目录下添加tabbar代码文件
custom-tab-bar/index

二、遇到的问题

  1. 自定义tabbar在实现中会出现tabbar切换页面时闪动的情况,该问题在社区反馈较多,官方暂时还没有解决方案。

  2. 为tabbar某一项添加右上角文本(badge)。每个tab页下的自定义tabbar实例是不同的,可以在app.globalData中定义全局变量保存所有tab页的自定义tabbar实例,添加文本时循环所有tabbar实例添加badge。

62.微信小程序怎么缓存数据?

有同步缓存和异步缓存

  • 异步缓存:wx.setStorage,wx.getStorage
  • 同步缓存:wx.setStorageSync,wx.getStorageSync
  • 清空缓存:wx.clearStorage、wx.clearStorageSync对本地缓存进行设置、获取和清理。

读取本地数据缓存接口的参数 :视情况选参

key:字符串类型,必填项,本地缓存中指定的key
success:异步接口调用成功的回调函数
fail:异步接口调用失败的回调函数
complete:异步接口调用结束的回调函数,无论成功失败都会执行

63.微信小程序怎么进行网络请求?

为了安全,微信小程序只能请求http类型接口,请求其他接口时必须将接口的域名添加到新人列表中。
在这里插入图片描述

配置request合法域名
登录微信小程序管理后台添加链接描述> 开发 -> 开发设置 -> 服务器域名 -> 修改 request 合法域名
注意:
① 域名只支持 https 协议
② 域名不能使用 IP 地址或 localhost
③ 域名必须经过 ICP 备案
④ 服务器域名一个月内最多可申请 5 次修改

网络数据请求
微信小程序支持GET,POST等请求。用method可以设置.
微信小程序提供了 wx.request(Object object) 这个API,用于发送网络请求,该API接受一个对象作为参数,该对象包含多个属性,其中常用的有:

url,请求的地址,string类型,必填。
data,请求的参数,可以是一个字符串或一个对象,非必填。
method,请求的方法,string类型,默认值是"GET"。
success,请求成功的回调函数,非必填。
fail,请求失败的回调函数,非必填。

发起get请求
调用微信小程序提供的 wx.request() 方法,可以发起 GET 数据请求.

getInfo(){
    vxwx.request({
      url: 'https://www.escook.cn/api/get',
      method:'GET',
      data:{
        name: 'zs',
        age:20
      },
      success:(res) => {
        console.log(res.data)
      }
    })
  },

发起post请求

getInfo(){
vxwx.request({
url: 'https://www.escook.cn/api/get',
method:'POST',
data:{
name: 'zs',
age:20
},
success:(res) => {
console.log(res.data)
}
})
}

页面加载时候就请求数据
可以在时间onload中定义fuction,调用get\post网络请求

onload: funtion(e){
postInfo();            
getInfo()

}
postInfo(){
}
getInfo(){
}

跨域和Ajax说明
跨域问题只存在于基于浏览器的 Web 开发中。由于小程序的宿主环境不是浏览器,而是微信客户端,所以小
程序中不存在跨域的问题。
Ajax 技术的核心是依赖于浏览器中的 XMLHttpRequest 这个对象,由于小程序的宿主环境是微信客户端,所
以小程序中不能叫做“发起 Ajax 请求”,而是叫做“发起网络数据请求”

64.微信小程序路由跳转以及传参如何实现?

有两种跳转方式:

  • 声明式:navigator 标签url=‘路径’ 可以使用绝对路径也可以使用相对路径
  • 编程式:利用js来跳转

小程序跳转注意事项:写路径的时候一定不要忘记加斜杠,理由:你如果不加斜杠的话,它就会在当前页面里面去找这个路径,那肯定找不到呀,因此写绝对路径时千万记得加斜杠。

wx.switchTab(Object object):
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,路径后不能带参数。

wx.reLaunch(Object object):
关闭所有页面,打开到应用内的某个页面。
需要跳转的应用内非 tabBar 的页面的路径 (代码包路径), 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔。

wx.redirectTo(Object object):
关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。可传参

wx.navigateTo(Object object):
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。

wx.navigateBack(Object object):
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。不可路径传参,其他都可。

路由传参:

//  第一种传参方式:字符串拼接   路径 ? 参数1=值 & 参数2=值 & 参数3=值
toShopCar(){
    wx.navigateTo({
        url:'/pages/pay/pay?username='+this.data.form.username+'&goodsNum='+this.data.form.goodsNum
    })
}
 
//  第二种传参方式:模板字符串 路径 ? 参数1=${值} & 参数2=${值}
toShopCar(){
    wx.navigateTo({
        url:`/pages/pay/pay?username=${this.data.form.username}&goodsNum=${this.data.form.goodsNum}`
    })
}

65.微信小程序生命周期的理解?

应用生命周期页面生命周期 组件(component)的生命周期
应用生命周期

App() 必须在 app.js 中调用,必须调用且只能调用一次,app.js中定义了一些应用的生命周期函数
(1)onLaunch: 初始化小程序时触发,全局只触发一次
(2)onShow: 小程序初始化完成或用户从后台切换到前台显示时触发
(3)onHide: 用户从前台切换到后台隐藏时触发
(4)onError: 小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
后台: 点击左上角关闭,或者按了设备 Home 键离开微信,并没有直接销毁,而是进入后台
前台:再次进入微信或再次打开小程序,相当于从后台进入前台。

页面生命周期

js文件中定义了一些页面生命周期函数,下面简述下这些生命周期函数的方法作用
(1)onLoad:首次进入页面加载时触发,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
(2)onShow:加载完成后、后台切到前台或重新进入页面时触发
(3)onReady:页面首次渲染完成时触发
(4)onHide:从前台切到后台或进入其他页面触发
(5)onUnload:页面卸载时触发

组件生命周期

created(重要):组件实例刚刚被创建好时触发
attached(重要):在组件完全初始化完毕、进入页面节点树后被触发
ready:在组件在视图层布局完成后执行
moved:在组件实例被移动到节点树另一个位置时执行
detached(重要):在组件离开页面节点树后被触发
error:每当组件方法抛出错误时执行

66.微信小程序模块化?

浏览器中,所有 JavaScript 是在运行在同一个作用域下的,定义的参数或者方法可以被后续加载的脚本访问或者改写。和浏览器不同,小程序中可以将任何一个JavaScript 文件作为一个模块,通过module.exports 或者 exports 对外暴露接口。

67.微信小程序所有api放在哪里,简单介绍几个api?

微信小程序的api一共分为三种
事件监听API 同步API 异步API

事件监听API:以on开头,用来监听某一些事件的触发;
例如:wx.onWindowResize(function callback)用来监听窗口尺寸大小的变化

同步API:以Sync结尾的api都是同步API。同步API的执行结果可以通过返回值直接获取,如果有错误会直接抛出异常。
例如:wx.setStorageSync(‘key’,‘value’)向本地存储中写入内容

异步API:类似与jQUery里面的ajax函数,需要通过返回类型success,fail接受调用的结果。
例如:wx.request(),发起网络请求,通过success回调函数接受数据。

68.微信小程序应用和页面生命周期触发顺序?

  1. 首次进入小程序会先触发应用生命周期中onLaunch方法和onShow方法,其次触发页面生命周期中onLoad、onShow和onReady方法。
  2. 前台切换到后台时,先触发页面生命周期中onHide方法,再触发应用生命周期的onHide方法。
  3. 后台切换到前台时,先触发应用生命周期中onShow方法,再触发页面生命周期的onShow方法。

69.微信小程序如何使用sass预编译?

我自己使用的是一下步骤就可以使用了

  1. 在vscode中下载一个 Easy Sass 插件如图所示
  2. 然后在 project.config.json 中的setting 中加入一个
  "setting": {
	...,
	"useCompilerPlugins": [
      "sass"
    ],
}

这行代码的意思就是 编译插件配置,基本上到这里就可以使用了,

  1. 修改 spook.easysass-0.0.6/package.json 文件中的配置在这里插入图片描述

  2. 重启开发者工具

以下字段是开发者工具的隐式设置
在这里插入图片描述

70.微信小程序开发文档界面都有哪些操作,列举几项?

在这里插入图片描述
在这里插入图片描述
等等的一些操作

  • 当我们想在小程序中实现一种布局,查看 组件
  • 当我们想在小程序中实现某一种功能,查看:API
  • 当我们想在小程序中想要进行某一个配置或者是某一种页面语法,就可以查看 :框架 + 指南
  • 还可以直接右上角搜索我们想要查看的功能

71.微信小程序自定义组件的使用?

  1. 打开项目文件目录,新建一个compoments目录。
    在这里插入图片描述
  2. 在里面新建一个tabs组件的目录,名称自定义。
    在这里插入图片描述
  3. 右键单击我们新建的tabs文件夹,新建component
    在这里插入图片描述
  4. 然后就会自动生成四个文件夹(因为我是配置了scss,所以会出现 .scss文件,没有配置的话会出现.wxss文件)
    在这里插入图片描述
  5. 来到要引用组件的页面中的json文件中(相当于父组件中),注册刚才设置的组件,也可以在全局进行一个配置,(app.json中)
    在这里插入图片描述
  6. 最后就是在tabs.wxml文件中写上页面,在.scss或者是.wxss文件中写上样式,
  7. 在需要的组件中将他引过去在这里插入图片描述
    在这里插入图片描述
  8. 最后这个自定义组件就显示在页面了

72.微信小程序事件通道的使用?

微信小程序事件通道(事件总线)是用于在小程序多个页面或组件之间通过触发事件进行通信的机制。
通过事件通道,一个页面或组件可以向事件通道发送一个事件,其他页面或组件可以通过监听该事件来获取消息并进行相应处理。

使用事件通道需要先在 app.js 中初始化事件总线:

App({
  onLaunch() {
    this.eventChannel = this.getEventChannelForPage();
  },
})

在需要发送事件的页面或组件中,通过wx.navigateTo或wx.redirectTo方法跳转到目标页面或组件时,传入events参数,并将它赋值为事件通道对象

wx.navigateTo({
  url: '/pages/targetPage/index',
  events: {
    someEvent: data => {
      // 收到事件,并执行相应操作
    }
  }
});

在目标页面或组件中,通过onLoad生命周期函数获得事件通道对象,并绑定事件处理函数:

onLoad(options) {
  const eventChannel = this.getOpenerEventChannel();
  eventChannel.on('someEvent', data => {
    // 处理事件
  });
}

当事件发生时,通过调用触发事件的方法,向事件通道中发送事件:

// 触发事件
this.eventChannel.emit('someEvent', data);

73.微信小程序如何使用vant组件库?

首先这是 vant weapp的网址
大家打开网站后,点击快速上手。上面就有步骤教你如何在小程序中使用vant组件库。
然后给大家介绍一下怎么使用组件库的,(其他的组件库依然可以使用)

  1. 打开我们小程序的项目目录,然后打开文件所在的位置。在这里插入图片描述
  2. 点击终端打开之后,初始化项目
    在这里插入图片描述
  3. 初始化的命令是

npm init 或者是 npm init -y
npm init 需要验证,一直回车,之后才能初始化
npm init -y 不需要验证,直接初始化

初始化之后,你会发现你的目录多出了package.json文件
在这里插入图片描述
4. 安装依赖 (直接复制安装即可)
4.1 通过 npm 安装vant/weapp

npm i @vant/weapp -S --production

4.2 安装 miniprogram

npm i miniprogram-sm-crypto --production

安装完毕后,你会发现你的目录中又多些文件。
在这里插入图片描述
4.3 修改 app.json

将 app.json 中的 “style”: “v2” 去除,原因是小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。

4.4 修改 project.config.json

开发者工具创建的项目,miniprogramRoot 默认为 miniprogram,package.json 在其外部,npm 构建无法正常工作。需要手动在 project.config.json 内添加如下配置,使开发者工具可以正确索引到 npm 依赖的位置。

{
  ...
  "setting": {
    ...
    "packNpmManually": flase,
    "packNpmRelationList": [
      {
        "packageJsonPath": "./package.json",
        "miniprogramNpmDistDir": "./miniprogram/"
      }
    ]
  }
}

4.5 构建 npm 我们点击左上角的工具栏
在这里插入图片描述
构建成功后会出现下面的画面
在这里插入图片描述

  1. 使用组件
    我这里在全局里面注册一个按钮,然后使用它。先去app.json中注册
    在这里插入图片描述
  "usingComponents": {
    "vant-button":"@vant/weapp/button/index",
    "Tabs":"./components/tabs/tabs"
  }

最后去使用一下组件
在wxml中:
在这里插入图片描述
在页面中的显示
在这里插入图片描述
我们就完成了

74.微信小程序自定义组件父传子子传父?

父向子组件传递数据

父组件(页面)向子组件传递数据,通过标签属性的方式来传递

(1)在子组件上进行接收

(2)把这个数据当成是data中的数据直接用即可

父传子
因为在前面我们写了自定义组件,所以我们就当他是子组件

  1. 在父组件的wxml文件中,在Tabs标签中添加属性,表示页面向子组件传递了属性aaa,值是a123a
    在这里插入图片描述

  2. 在子组件的js文件中,在properties中接收父组件传递的数据,properties里面要填接收的数据的名称,这里的名称是aaa,aaa是个对象,里面写数据的类型和数据的值,数据的值不填就默认是上面的值“a123a",填了数据值,值就是我们写的那个值
    在这里插入图片描述

  3. 在子组件的wxml中,使用数据的名称
    在这里插入图片描述
    效果:
    在这里插入图片描述

父传子的过程
在这里插入图片描述
传递data数据怎么传?

  1. 在父组件中的data中写数据
    在这里插入图片描述

  2. 父组件的wxml中传递tabs数据
    在这里插入图片描述

  3. 子组件.js文件中接收tabs数据在这里插入图片描述

  4. 使用数据的名称
    在这里插入图片描述
    最后的效果:
    在这里插入图片描述

子传父
子向父传递数据,通过事件的方式传递

  1. 子组件绑定函数 addInfo
 <button type="primary" bindtap="addInfo">确定</button>
  1. 子组件定义函数addInfo
   addInfo(){
      let item = {title:'测试',money:8,category:'吃饭'}//要传给父组件的参数
      this.triggerEvent('addInfo',item)//通过triggerEvent将参数传给父组件
    },
  1. 父组件绑定自定义点击函数
<add-item nowAddDate="{{isShowAdd}}" bind:addInfo="getAddInfo"></add-item>
  1. 父组件接收子组件传过来的参数
  getAddInfo(e){
    console.log(e.detail)//{title:'测试',money:8,category:'吃饭'} 
},

最后:一个共就两个函数注意就好了,子组件中的addInfo 和 父组件的 getAddInfo

75.微信小程序自定义组件生命周期有哪些?

生命周期函数

created:在组件实例刚被创建时执行
attached:在组件实例进入页面节点树时执行
ready:在组件在视图层布局完成后执行
moved :在组件实例被移动到节点树另一个位置时执行
detached:在组件实例被从页面节点树移除时执行
error:每当组件方法抛出错误时执行

最重要的生命周期函数有3个,分别是created、attached、detached

  • 组件实例刚被创建好时触发created生命周期函数
    此时不能调用setData,只能添加一些自定义的属性字段

  • 在组件初始化完毕,进入页面节点树时触发attched生命周期函数
    此时,this.data初始化完毕,数据初始化的操作可以在此操作

  • 在组件离开页面节点时,触发detached生命周期函数
    退出页面时触发,可以做一些清理数据方面的操作

76.微信小程序授权登录流程?

在这里插入图片描述
总结:

  1. 在进入小程序的时候要判断是否有授权,如果没有授权,则要先授权之后,才能登陆到小程序的首页。
    刚开始,我把login页当作了小程序的首页,这样导致如果已经授权过,这个页面也会一闪而过。用户体验不好。捋了一下思路之后认为,应该把授权的判断放在app.js中onLaunch生命周期里,首页还是正常的index页面。
    若已经授权,获取用户信息,存在全局的data里,若没有授权,跳转到login页,进行授权操作

  2. 授权成功,获取用户信息成功之后,将用户信息存储在本地缓存中指定的 userInfo 中,然后跳转到小程序首页

  3. 之后不论在哪个页面,如果需要用户信息,从本地缓存中异步获取指定 userInfo 的内容即可

77.web-view

承载网页的容器。会自动铺满整个小程序页面

、首先,web-view有以下限制:

  1. 个人开发者无法使用
  2. 需要配置域名,且域名需ICP备案24小时以上,不支持ip及端口
  3. 需使用https
  4. 每个小程序账号仅支持配置20个域名,每个域名最多绑定20个小程序,每个小程序一年内最多支持修改域名50次

、然后看看web-view如何加载html

<web-view src="https://www.itlao5.com"></web-view>

很简单,一行代码搞定,小程序中的web-view会自动占据整个页面,所以无法在web-view上再覆盖view

、web-view交互

  1. 用户可以通过传参给web-view中的html
  2. 网页可以使用wx.miniProgram.navigateTo、wx.miniProgram.navigateBack等接口控制小程序的跳转,并传值
  3. 网页可以调用JSSDK指定的js方法
  4. 用户分享时可获取当前web-view的url,即在onShareAppMessage回调中返回webViewUrl参数。 示例代码:
Page({
  onShareAppMessage(options) {
    console.log(options.webViewUrl)
  }
})

、使用注意

  1. ios若jssdk接口调用无响应,可在的src后加上#wechat_redirect试试
  2. web-view空白问题,请升级微信客户端到 6.5.16
  3. web-view不支持支付

点击查看详情

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值