# vue 面试题
性能优化:
1.passive 是性能优化的一种方案,如果有 passive 那么意味着 event 对象下不能使用 preventDefault 函数。
> 系统去执行某个程序时,因为不知道这个程序中是否写了阻止默认行为的代码,所以会提前预留一些资源,如果在绑定事件时使用了passive,那么系统就知道这个关联函数中一定没有 preventDefault ,所以就不预留资源了。
<div @scroll.passive="fn"> //不能和.prevent 和e.preventfault()共用,否则浏览器会报错
计算属性,虚拟节点
el:提供一个已存在的 DOM 元素作为 Vue 实例的挂载目标,在实例挂载之后,元素可以用 vm.$el 访问
## (重要)vue的核心,数据双向绑定的原理,mvvm的原理?
答:Object.defineProperty() 相关的内容
vue的核心:
数据驱动:利用的是ES5的Object.defineProperty和存储器属性: getter和setter,核心是VM,即ViewModel,保证数据和视图的一致性。
组件系统:应用类UI可以看作全部是由组件树构成的。组件可以扩展HTML元素,封装可重用的代码,提高代码的重用性
数据双向绑定的原理:
而在vue中实现双向数据绑定的原理是:采用数据劫持结合发布者-订阅者的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时,发布消息给订阅者,触发相应的监听回调。通俗的讲,就是利用数据监听器observe(对数据对象的所有属性进行监听)监听Model层的数据变化;利用指令解析器Compile(写一些更新函数)来编译解析模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 (model)-》视图更新(view);视图变化(view)-》数据(model)变更的双向绑定效果。
VUE实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。defineProperty的用法var obj = { };var name;//第一个参数:定义属性的对象。//第二个参数:要定义或修改的属性的名称。//第三个参数:将被定义或修改的属性描述符。
vue.js是一种基于MVVM方式的框架,专注于MVVM模型的ViewModel层,通过双向数据绑定的方式将Model层和View层连接起来。
mvvm的原理:m:模型层:存放数据和业务逻辑
v:视图层,把模型层的数据显示在页面
VM:视图模型层:是模型层和视图层的桥梁,两者不能直接关联。
原理:通过es5的Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时,发布消息给订阅者,触发相应的监听回调。达到当数据变化 (model)-》视图更新(view);视图变化(view)-》数据(model)变更的双向绑定效果。
1.实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者
var obj={
age:18,
name:'zhou'
};
var val=obj[name];
Object.defineProperty(obj,"name",{
set(v){
console.log("修改name为:"+v);
val=text.value=span.innerHTML=v; //21行的val在最初的时候只有个初始值,所以这里要将val更新 ,v就是更新后的值
},
get(){
console.log("获取了");
return val;
}
})
text.onkeyup=()=>{
obj.name=text.value;
}
## vue 与 jquery 的区别?
答:数据驱动、编程式渲染、模版相关的内容
从jquery到vue或者说是到mvvm的转变是一个思想的转变,是将原有的直接操作dom的思想转变到操作数据上去
jquery是操作DOM对象,数据和界面是在一起的。
Vue则是操作数据,通过Vue对象将数据和View完全分离开来,通过Vue对象这个vm实现相互的绑定。
vue侧重数据绑定,jquery侧重样式操作,动画效果等
## v-if 与 v-show 的区别?
v-if是对dom节点的创建与销毁
v-show是改变元素的display属性值
v-if有更大的切换开销,频繁切换的时候用v-show
切换较少的时候用v-if
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
## v-html 、v-text 、v-once 区别?
v-text:以文本的形式渲染
v-html:以html的形式渲染
v-once:只绑定一次,后面再使用的话将不再更新
vue采用就地复用原则:Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。(子节点就地复用)
如果不想采用就地复用,请使用key
key:不使用key时(a,b,c三个复选框,当选中a时,然后删除a(splice删除数组元素)),发现a正常被删除了,而b却被选中了。
key为下标时也一样的效果,因为a对应的下标是0,当删除a时,b的下标就变为0了,key会随着改变,所以b被选中,。
vue采用就地复用原则:Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。(子节点就地复用)
如果不想采用就地复用,请使用key,且不为下标
## 计算属性缓存是怎么一回事?
计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值。相比之下,每当触发重新渲染时,调用methods中方法将总会再次执行函数。
## 计算属性缓存
1.watch擅长处理的场景:一个数据影响多个数据 结算
2.computed擅长处理的场景:一个数据受多个数据影响 搜索框 v-model+watch+dataList
注意:视图层不建议使用methods函数,该需求应该用计算属性代替。
```html
<div id="app">
{{str}}
<input type="text" v-model="a" />
+
<input type="text" v-model="b" />
=
{{c}} <br> {{d()}}
</div>
<script>
var vm = new Vue({
el:"#app",
data(){
return {
str : "加法运算",
a : 1,
b : 2
}
},
computed:{ // 推荐用计算属性 (因为计算属性有缓存)
c(){
console.log('c 执行了');
return Number(this.a) + Number(this.b);
}
},
methods:{ // 不推荐用方法
d(){
console.log('d 执行了');
return Number(this.a) + Number(this.b);
},
e(){
console.log('e 执行了')
}
}
})
// 执行 vm.str="abc" 时,这段代码与视图层的d()没有任何关系,但是d()被执行了,
// 意味着只要视图发生变化,视图层的方法都会被执行
</script>
## 全局组件和局部组件的区别?及如何创建及使用
## 一、使用范围:
全局组件使用范围:可以在页面中任何位置使用
局部组件使用范围:只能在定义它的el中使用,不能再其他位置使用,否则就无法生效
二、定义组件的方法:
全局组件:可以使用Vue.component(tagName,options)定义全局组件
局部组件:可以通过Vue实例中component属性定义局部组件
```javascript
Vue.component('my-component-name', {
template:'<div>abc</div>'
})
```
```html
<my-component-name> </my-component-name>
```
## 局部组件
```
<div id="app"><hi></hi></div>
<script>
var app = new Vue({
el: '#app',
components: {
'hi': {"template": "<h1>hi</h1>"}
}
})
</script>
## 在单文件组件中,如何创建、导入、注册、使用组件?
1.可在src目录下新建一个文件名为MyComponents,在文件中新建一个文件夹,可命名为Home.vue
template>
<div id="app">
<!-- 组件的使用 -->
<v-Home></v-Home>
</div>
</template>
<script>
// 导入组件
import Home from './MyComponents/Home.vue'
export default{
name:"App",
// 注册组件
components:{
'v-Home':Home
},
data(){
return{
}
}
}
</script>
<style lang="sass" scoped>
// scoped 作用于当前的组件样式
</style>
## 过滤器函数是怎么一回事?(来一段示例代码)
```html
{{ 2 | r(3) }}
```
```javascript
Vue.filter('r', function (value, d) {
return value*d
})
```
局部
```html
{{ 2 | r(3) }} 若有多个过滤器,可以用|在前者的前提下继续过滤
```
```javascript
new Vue({
filters: {
r(value, d) {
return value*d
}
}
})
## 自定义指令是怎么一回事?(来一段示例代码)
# directive 指令
全局:
```javascript
Vue.directive('focus', {
inserted(el[,binding,vnode]) {
//可以用switch(el.tagName.toLowerCase()){}限制元素类型
//switch(el.tagName.toLowerCase()){
case "span":el.innerHTML="绑定成功";
break;
default:console.log(Promise.reject(el.tagName.toLowerCase()+" is not allowed to bind this directive"));
el.focus() //binding.value arg: "冒号后的值" expression: "等号后的值" value: "data中的值"
}
/*1.vue自定义指令钩子函数:
bind(){} 当指令绑定到 HTML 元素上时触发.只调用一次.
inserted() 当绑定了指令的这个HTML元素插入到父元素上时触发(在这里父元素是 div#app).但不保证,父元素已经插入了 DOM 文档.
updated(el, binding,vnode,oldVnode) 所在组件的VNode更新时调用.
componentUpdate((el, binding,vnode,oldVnode)) 指令所在的组件的VNode以及其子VNode 全部更新后调用.
unbind: 指令和元素解绑的时候调用,只调用一次*/
})
```
局部:
```javascript
directives: {
focus: {
inserted(el, binding, vnode) { //el就是绑定的元素
el.focus()
}
}
}
```
使用:
```html
<input v-focus>
## 生命周期钩子函数都有哪些?
## 每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。
## // 创建阶段
beforeCreate(){
console.log("beforeCreate实例初始化之后,数据观测和事件配置还未完成时")
},
created(){
console.log("created实例创建完成后立即调用")
},
beforeMount(){
console.log("beforeMount在挂载开始之前被调用(挂到html上)")
},
mounted(){
console.log("mounted挂载完成后被调用")
},
// 运行阶段
beforeUpdate(){
console.log("beforeUpdate数据更新时被调用(更新DOM前)")
},
updated(){
console.log("updated数据更新导致DOM重新渲染后被调用")
},
// 销毁阶段
beforeDestroy(){
console.log("beforeDestroy实例销毁前被调用")
},
destroyed(){
console.log("destroyed实例销毁后被调用")
}
## 了解多少种数据传递的方法?他们分别是什么?
## 1.slot插槽:简单的说,就是向组件内部传入数据,在组件内部,使用slot标签表示传入到组件中的数据。
## 普通的数据用prop传递,html结构的这种数据用slot传递
## <abc>百度</abc> template:"<div><slot></slot></div>"
## 具名插槽:
**app.vue**
```html
<Hello>
<template v-slot:title>标题</template> //简写 #title 该缩写只在其有参数的时候才可用
内容
<template v-slot:footer>脚底</template>
</Hello>
```
**hello.vue**
```html
<slot name="title"></slot>
<slot></slot>
<slot name="footer"></slot>
> v-slot 只能添加在 template 上
> slot标签没有name属性时,解析的是 v-slot:default
> slot内容如果没有用template和v-slot指定名称,那么属于default
##
## 2. props:父传子
## <script>
Vue.component("fa",{
"template":"<div><ch a=58></ch><div>" //父组件中自定义一个属性
})
Vue.component("ch",{
"template":"<div>我是孩子{{a}}<div>",
props:['a'] //子组件中用props接收
})
var app = new Vue({
el: '#app',
data : {
},
## 3. $emit:子传父 父组件自定义事件,子组件用this.$emit("父组件自定义事件名",[参数])触发
## <script>
Vue.component("fa",{
"template":"<div>爸爸<ch @ba='fa'></ch><div>" ,
methods:{
fa(n){
alert(n)
}
}
})
Vue.component("ch",{
"template":"<div>我是孩子<button @click='ch'>按钮</button><div>",
methods:{
ch(){
this.$emit("ba",8); //触发父级的自定义事件
}
}
})
var app = new Vue({
el: '#app',
})
</script>
# 4.EventBus中央事件总线. 创建一个vue实例 在一个组件中用$on定义,在另一个组件中用$emit触发 不同组件中数据的共享
解决复杂组件关系中,数据维护的问题。
Vue.prototype.$eventbus=new Vue();
Vue.prototype.$alert=function(n){
this.$eventbus.$emit('alert',n);
}
另一个组件中:
mounted(){
this.$eventbus.$on("alert",function(n){
alert(n)
})
}
使用:this.$alert(10);
6.### 依赖注入
provide 和 inject 必须在一条线路上,爷爷提供了方法,孙子使用方法,这是可以的;如果叔叔提供了方法,侄子使用方法,是不可以的
- provide (提供给后代组件的方法)
- inject(接收前代组件提供的方法)
Vue.component('abc', {
template:`
<div>1<xyz></xyz></div>
`,
provide(){ return { abc:this.fn } },
methods:{ fn(){alert()} }
})
Vue.component('xyz', {
template:`
<div><button @click='abc'>2</button></div>
`,
inject:["abc"]
})
##
7.### 访问组件
- $root 指跟
- $parent 指父
- $children 指子
- $refs 当前页面中查找
8.vuex
状态管理(重点) vuex 需要独立安装,用来解决数据存储和维护的问题
使用:
1.npm i vuex -S
2.store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
let store=new Vuex.Store({
state:{
item:[1,2,3]
},
getters:{},
mutations:{},
actions:{}
})
export default store;
3.main.js
import store from './store/store.js';
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')
属性:
- state 用来存储状态的容器
state:{
item:[1,2,3]
}
- mutations 用来存储改变state的方法的容器
mutations:{
setNum(state,payload){
state.item.push(payload)
}
}
- actions 用来存储异步代码和业务逻辑代码,组件页用户触发的是这个函数
actions:{
setNum(context,payload){
context.commit("setNum",payload);
}
}
- getters 类似计算属性
getters:{
show(state){
return state.item;
}
}
- modules 状态特别多时,可以用modules将状态进行分类
this.$store.state.g.goods //g模块下的goods
store.js
import .......
import cart from './cart.js'
const store = new Vuex.Store(
{
modules: {
adress,
cart
}
})
export default store
cart.js
const cart={
namespaced:true, //使用命名空间
state={},
getters:{},
...
}
export...
组件触发:
methods:{
add(){
this.$store.dispatch("a/setNum",parseInt(Math.random()*3)) //a模块下的setNum
this.$store.dispatch("setNum",parseInt(Math.random()*3)) //所有模块的setNum
}
}
订阅事件:
store.subscribe((mutation, state)=>{
// 每次执行完 mutation 后,该订阅函数会被自动触发
})
区分 actions 和 mutations 并不是为了解决竞态问题,而是为了能用 devtools 追踪状态变化
mutation 必须是同步,意义在于这样每一个 mutation 执行完成后都可以对应到一个新的状态(和 reducer 一样),这样 devtools 就可以打个 snapshot 存下来
亲测: 如果在mutation中做了异步操作,在dev-tools中会立即打印一个snapshot,而此时异步操作还没有执行完,此时的snapshot的信息是错误的。
而在action中做异步操作dev-tools会等等异步操作执行完才去打印mutation的一个snapshot,这样便于我们回查time-travel,查看在某个mutation里的变化。
辅助函数的使用:
import {mapState,mapMutations,mapActions,mapGetters} from "vuex"
state的辅助函数需要映射到计算属性中computed,映射的名称一定要相同,然后就可以通过this访问到state
computed:{
// ...mapState(["item"]) //name和vuex中的state保持一至。
...mapState({ //用了模块化后
item:(state,getters)=>{
return state.cang.item;
}
})
},
methods:{
click(){
console.log(this.name)//访问到vuex的name
}
}
mutation的辅助函数mapMutations把mutations里面的方法映射到methods中
methods:{
// ...mapMutations(["show"])
...mapGetters({ //用了命名空间后
"show":"cang/show"
}),
click(){
this.show()
},
}
mapAcions:把actions里面的方法映射到methods中
methods:{
// ...mapActions(['setNum'])
...mapActions({ //用了命名空间后
setNum:"cang/setNum"
})
}
mapGetters:把getters属性映射到computed身上
## 如何实现spa?什么是编程式导航?什么是路由守卫?
路由机制去实现
声明式:this.$router.replace()
编程式:this.$router.push()/replace()
路由守卫:
全局路由守卫:
router.beforeEach((to, from, next) => {
console.log(to) => // 到哪个页面去?
console.log(from) => // 从哪个页面来?
next() => // 执行跳转
}
router.afterEach(to,from) = {}
组件路由守卫:
// 跟methods: {}等同级别书写,组件路由守卫是写在每个单独的vue文件里面的路由守卫
beforeRouteEnter (to, from, next) {
// 注意,在路由进入之前,组件实例还未渲染,所以无法获取this实例,只能通过vm来访问组件实例
next(vm => {})
}
beforeRouteUpdate (to, from, next) {
// 同一页面,刷新不同数据时调用,
}
beforeRouteLeave (to, from, next) {
// 离开当前路由页面时调用
}
路由独享守卫:
routes: [
{
path: '/',
name: 'home',
component: 'Home',
beforeEnter: (to, from, next) => {
// ...
}
}
]
## # SPA 单页面应用开发(重点)
SPA 的优势:因为是把页面都合并到一起,所以路由切换时,实际上是在当前页面切换显示,所以不会因网络问题造成页面卡顿、白屏。
SPA 的不足:合并后的文件体积特别的大,所以第一次打开页面时,比较慢。(解决方法是用按需加载)
用前端路由来实现。
SPA:单页面,页面无刷新,跳转无刷新,前端路由实现。
路由实现:
# router 路由(重点)
vue-router 配置基于 vue 的单页面应用(SPA)
首先安装路由模块
```bash
npm install vue-router -S
```
在 src 目录下,新建 router.js 文件,在里面写入如下代码:
```javascript
import Vue from 'vue'
import VueRouter from 'vue-router';
// 导入一些页面级别的组件(这些组件需要自己创建)
import Index from './pages/Index.vue'
import Goods from './pages/Goods.vue'
import Buycar from './pages/Buycar.vue'
import Mine from './pages/Mine.vue'
// 将vue-router注册到全局,这样每一个组件都可以使用router-link和router-view组件了
Vue.use(VueRouter);
// 定义路由规则(例如:当用户访问了/goods这个页面时,router-view标签渲染Goods组件)
var routes = [
{ path: '/', component: Index },
{ path: '/goods', component: Goods, children: [
{ path: '/user/register', component: RegisterComponent },
{ path: '/user/login', component: LoginComponent }
]},
{ path: '/buycar', component: Buycar },
{ path: '/mine', component: Mine },
]
// 创建路由实例
var router = new VueRouter({ routes, mode:'history' });
// 导出路由对象
export default router
```
在 src 目录下,找到 main.js 文件,在其中修改:
```javascript
// 导入路由配置文件
import router from './router.js'
new Vue({
router, // 让每个vue组件中可以使用 $route 和 $router 对象
render: h => h(App),
}).$mount('#app')
```
- router-link 组件:渲染后为a标签,点击这个标签后,浏览器地址栏会发生变化。
- router-view 组件:浏览器地址栏每次发生变化时,会根据路由规则,把匹配到的组件显示到router-view标签上。
```html
<router-view></router-view>
```
在 src/components/footer.vue 文件中
```html
<router-link to="/">首页</router-link>
<router-link to="/goods">商品</router-link>
<router-link to="/buycar">购物车</router-link>
<router-link to="/mine">我的</router-link>
```
原理:
1.hash模式:
hash值改变 》不包括在http请求当中 》 浏览器不会对服务器发送请求 》页面不刷新 》而且hash值改变会触发hashchange事件》可得知hash值的变化 》做一些页面更新的操作
2. history 模式
HTML5 History Interface 中新增的 pushState() 和 replaceState()方法》
应用于浏览器的历史记录栈》在原有的back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能,调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件,因此即使url发生改变,但是浏览器不会立即向后端发送请求。 popstate事件只会在浏览器某些行为下触发, 比如点击后退、前进按钮.
强制刷新会报404错误,vue-router设置的路径不是真实存在的路径,所以刷新就会返回404错误,需要后台做一个重定向,要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面。
# 路由中如何传递参数?
#
this.$route.query/params
答:query 和 params
## (重要)vue中路由实现的原理?
答:利用 URL 的 hash(#) 和 利用 H5 新增方法 History interface
## 如何实现动画效果
<transition
enter-class=""
enter-active-class="animated fadeIn"
enter-to-class=""
leave-class=""
leave-active-class="animated fadeOut"
leave-to-class=""
>
<div class="toast" v-if="isShow">Toast</div>
</transition>
transition只能有0个或1个子节点,而transition-group可以有零个或多个子节点。
循环渲染时,必须写key,并且key的值是唯一标识符(不要用数组下标)。
## (重要)vuex 是什么?与eventbus的区别是什么?
vuex:集中式状态管理模式,可以实现多个组件之间的数据共享
当涉及的组件较多时,用vuex,较少时用eventbus,否则过多的组件之间用eventbus的话会变得非常复杂混乱。
## (重要)nuxtjs是什么? ssr与bsr的区别?
Nuxt.js 是基于 vue 的服务器端渲染框架。
**客户端渲染**
前端利用ajax等数据交互手段获取服务端提供的数据之后,渲染到HTML页面。
优点:灵活,真正的前后端分离,方便于前后台各自更新维护
缺点: 对SEO不友好,增加了http请求次数,减缓了页面加载速度
**服务器端渲染**
整个网站先在服务器中运行,然后返回一个完整的HTML字符串,将这个字符串当成响应内容输出给浏览器。
**SSR优势**
- 利于搜索引擎抓取我们的页面。
- build之后,会静态化page页面,所以访问速度快。
- 网络爬中就可以抓取到完整页面的信息。
优点: 对SEO友好,减少了http请求次数,加速了页面初次渲染速度
缺点: 不灵活,前后端耦合度太高
## (重要)是否封装过UI组件?是否创建过插件?是否创建共全局组件
答:plugin插件的应用
全局组件:
src/plugin/abc.js
export default {
install(Vue,options){ // install 是默认的方法。当外界在 use 这个组件的时候,就会调用本身的 install 方法,同时传一个 Vue 这个类的参数。
Vue.component(options.a,{
render(createElement){
return createElement("div",`这是全局组件${options.b}`)
}
})
}
}
main.js
import ABC from './plugin/abc.js';
Vue.use(ABC,{
a:'abc',
b:"你好啊"
}) //第二个是传参
其他页面可以<abc></abc>直接用
封装UI插件:
1.创建plugin.js文件和toast.vue文件
<template>
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<div class="toast" v-if="show">{{txt}}</div>
</transition>
</template>
<script>
export default {
data(){
return {
txt : "",
show : false
}
}
}
</script>
<style></style>
....
main.js中导入:import toast from './plugin/plugin.js'
然后用Vue.use(toast);
2.plugin.js
import to from '......toast.vue';
export{
install(Vue [,options]){
const Com=Vue.extend(toast); //拓展方法,Toast是独立的组件,extend的作用是将Toast与Vue项目关联起来
const vm=new Com().$mount(); //组件实例化,使用$mount可以获取Toast组件的vm层
document.body.appendChild(vm.$el); //把Toast组件的视图部分挂到vue项目的body上
Vue.prototype.$toast=function(text){
vm.show=true;
vm.txt=text;
console.log("我只行啦")
setTimeout(()=>{
vm.show=false;
},2000)
}
}
}
3.使用
任何页面通过this.$toast("你好")调用组件
注意组件绑定事件要用.native 绑定一个原生的事件,如<abc></abc>
--------------------------------------------------------------------
1.在父元素中滚动,父元素不被撑开
.fa{
background: yellow;
width: 200px;
height: 200px;
overflow: auto;
}
.ch{
background: red;
width: 200px;
height: 5000px;
}
2.
proxy原理:将请求发给自己的后台,再由后台去请求目标网址。
在项目根目录,自己创建 vue.config.js 文件,里面写入:修改后记得重启项目
```javascript
module.exports = {
devServer: {
proxy:{
"/a": {
target: "http://www.zhouyuefei.xyz",
pathRewrite: { '^/a': '' },
changeOrigin: true,
},
"/b": {
target: "http://www.wyyijiaqin.com",
pathRewrite: { '^/b': '' },
changeOrigin: true,
}
}
}
}
3. top = ele.getBoundingClientRect().top;//getBoundingClientRect().top一个元素距离页面顶端的距离
4. v-clock能够解决插值表达式闪烁问题
[v-clock]{
display: none;
}
<div v-clock>
{{msg}}
</div>
v-clock的作用就是vue对模版内容编译之前,先给该元素添加个css样式,等到编译完成后,再把样式取消掉。
注意:过滤器可以过滤时间