vue基础

20 篇文章 1 订阅

vue学习整理

http://doc.liangxinghua.com/vue-family/1.html

说一下 Vue 和 React 的认识,做一个简单的对比

监听数据变化的实现原理不同

Vue 通过 getter/setter 以及一些函数的劫持,能精确快速的计算出 Virtual DOM 的差异。这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
React 默认是通过比较引用的方式进行的,如果不优化,每当应用的状态被改变时,全部子组件都会重新渲染,可能导致大量不必要的 VDOM 的重新渲染。
Vue 不需要特别的优化就能达到很好的性能,而对于 React 而言,需要通过 PureComponent/shouldComponentUpdate 这个生命周期方法来进行控制。如果你的应用中,交互复杂,需要处理大量的 UI 变化,那么使用 Virtual DOM 是一个好主意。如果你更新元素并不频繁,那么 Virtual DOM 并不一定适用,性能很可能还不如直接操控 DOM。

  为什么 React 不精确监听数据变化呢?这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而 React 更强调数据的不可变。

数据流的不同
Vue 中默认支持双向绑定,组件与 DOM 之间可以通过 v-model 双向绑定。但是,父子组件之间,props 在 2.x 版本是单向数据流
React 一直提倡的是单向数据流,他称之为 onChange/setState()模式。
不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。

模板渲染方式的不同
在表层上, 模板的语法不同
React 是通过 JSX 渲染模板
而 Vue 是通过一种拓展的 HTML 语法进行渲染
在深层上,模板的原理不同,这才是他们的本质区别:

React 是在组件 JS 代码中,通过原生 JS 实现模板中的常见语法,比如插值,条件,循环等,都是通过 JS 语法实现的
Vue 是在和组件 JS 代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现
对这一点,我个人比较喜欢 React 的做法,因为他更加纯粹更加原生,而 Vue 的做法显得有些独特,会把 HTML 弄得很乱。举个例子,说明 React 的好处:react 中 render 函数是支持闭包特性的,所以我们 import 的组件在 render 中可以直接调用。但是在 Vue 中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们 import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。

Vue 的 nextTick 的原理是什么?

为什么需要 nextTick
Vue 是异步修改 DOM 的并且不鼓励开发者直接接触 DOM,但有时候业务需要必须对数据更改–刷新后的 DOM 做相应的处理,这时候就可以使用 Vue.nextTick(callback)这个 api 了。

理解原理前的准备
首先需要知道事件循环中宏任务和微任务这两个概念(这其实也是面试常考点)请阅大佬文章–彻底搞懂浏览器 Event-loop
常见的宏任务有 script, setTimeout, setInterval, setImmediate, I/O, UI rendering
常见的微任务有 process.nextTick(Nodejs),Promise.then(), MutationObserver;

理解 nextTick
而 nextTick 的原理正是 vue 通过异步队列控制 DOM 更新和 nextTick 回调函数先后执行的方式。如果大家看过这部分的源码,会发现其中做了很多 isNative()的判断,因为这里还存在兼容性优雅降级的问题。可见 Vue 开发团队的深思熟虑,对性能的良苦用心。
如果你比较了解了前面的事件循环原理,推荐你看看这篇文章 请阅大佬文章–全面解析 Vue.nextTick 实现原理

vue框架的理解

vue是(渐进式表现:)声明式渲染—组件系统—客户端路由—大数据状态管理—构建工具的一款渐进式框架

vue的两个核心点

(1)响应式数据绑定
当数据发生变化的时候,视图自动更新,即双向数据同步,原理利用了ES6中的 Object.definedProperty 中的setter/getter 代理数据,监控对数据的操作。
(2)组合的视图组件
即页面最终映射为一个组件树,采用树形数据结构进行设计,方便维护,重用。

关于MVVM

MVVM 是 Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式, 其核心是提供对 View 和 ViewModel 的双向数据绑定,这使得 ViewModel 的状态改变可以自动传递给 View,即所谓的数据双向绑定。
M:Model(数据层,也就是指数据(前端是js))
V:View ( 也就是指DOM层 或用户界面 )
VM : ViewModel (处理数据和界面的中间层,也就是指Vue) Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。

在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

mvvm和mvc区别?它和其它框架(jquery)的区别是什么?哪些场景适合?

主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。

区别:vue数据驱动,通过数据来显示视图层而不是节点操作。

场景:数据操作比较多的场景,更加便捷

vue全家桶

vue + vue-router + vuex + axios
https://www.cnblogs.com/Nutrient-rich/p/7063058.html

vue中获取dom,及操作dom

  • 练习获取dom

1选择器获取,2ref获取

//选择器获取                                                                                                                                  <template>
    <div>
        <canvas id='cvs' >
    </div>
</template>
<script>
    export default{
        mounted(){
            let canvas=document.querySelector('#cvs');
        }
    }
</script>
ref获取                                                                                                                                            <template>
    <div>
        <canvas ref='cvs' >
    </div>
</template>
<script>
    export default{
        mounted(){
            let canvas=this.$refs.cvs;
        }
    }
</script>

在watch或者created里面操作dom,用this.$nextTick(function(){
xxxx
})

vue获取后端数据应该在created还是mounted

看情况了,一般放到created里面就可以了,这样可以及早发请求获取数据,如果有依赖dom必须存在的情况,就放到mounted(){this.$nextTick(() => { /* code */ })}里面

vue指令

v-text

解释:更新元素的 textContent

v-html

解释:更新元素的 innerHTML


v-bind

作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
语法:v-bind:title=“msg”
简写::title=“msg”

v-on

作用:绑定事件
语法:v-on:click=“say” or v-on:click=“say(‘参数’, $event)”
简写:@click=“say”
说明:绑定的事件从methods中获取

事件修饰符

.stop 阻止冒泡,调用 event.stopPropagation()
.prevent 阻止默认事件,调用 event.preventDefault()
.capture 添加事件侦听器时使用事件捕获模式
.self 只当事件在该元素本身(比如不是子元素)触发时触发回调
.once 事件只触发一次

v-model

作用:在表单元素上创建双向数据绑定
说明:监听用户的输入事件以更新数据

v-for

作用:基于源数据多次渲染元素或模板块

v-for循环key属性

vue中的v-for循环最好加上key属性,否则在高版本(2.2.0+)的vue中控制台会报错。

key属性需要唯一,理想的 key 值是每项都有唯一 id,全局不需唯一,但在一个循环中需要唯一

为什么使用key?
当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容

key属性

推荐:使用 v-for 的时候提供 key 属性,以获得性能提升。
说明:使用 key,VUE会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

样式处理 -class和style

说明:这两个都是HTML元素的属性,使用v-bind,只需要通过表达式计算出字符串结果即可
表达式的类型:字符串、数组、对象
语法:

===>

为什么避免 v-if 和 v-for 用在一起

当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,通过v-if 移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在 v-if 为否的时候运算 v-for。

v-if 和 v-show

条件渲染
v-if:根据表达式的值的真假条件,销毁或重建元素
v-show:根据表达式之真假值,切换元素的 display CSS 属性

不同点:

1 . v-if 当值为 true时,显示div ,

    当值为false时,改元素消失,代码也会消失,

    相当于将代码删除了,当在为true时,页面会重新渲染div; 

    支持加在<template>标签上



    而v-show 控制的隐藏出现,

    只是将css属性设为了display:none 或block;

   不支持加在<template>标签上

2.v-if 后还有 v-else 和 v-else-if 条件渲染,

这里需要注意的是v-else 必须紧跟 v-if 或v-else-if 

3.v-if是真真正正的条件渲染;

然而他是惰性的,

在初始值是false的时候,他就什么都不做,

在为真的时候才会开始局部变异

  相比之下v-show则是更简单一下,仅仅是css上的切换 

  所以,v-if有更高的切换消耗,

  而v-show有更高的初始渲染消耗;

  因此,如果是频繁切换,就用v-show;

  在条件很难改变,比如某个模块在用户a出显示,就用v-if

提升用户体验:v-cloak

这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
防止刷新页面,网速慢的情况下出现{{ message }}等数据格式

{{ message }}

提升性能:v-pre

说明:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
{{ this will not be compiled }}

提升性能:v-once

说明:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
This will never change: {{msg}}

组件

全局

全局组件注册方式:Vue.component(组件名,{方法})

注意:

全局组件必须写在Vue实例创建之前,才在该根元素下面生效;

模板里面第一级只能有一个标签,不能并行;

data里面this指的是window,在methods里面this才是Vue实例

局部

局部组件注册方式,直接在Vue实例里面注册
    new Vue({

  el: '#app',

  router,

  components: { App },

  template: '<App/>'

})

注意:

属性名为components,s千万别忘了;

data里面this指的是window,在methods里面this才是Vue实例

组件的属性以及用法和意义

data:data必须是一个函数 返回一个唯一的对象,不要和其他组件共用一个对象进行返回!!!每一个实例的data属性都是独立的,不会相互影响了

watch

首先确认 watch是一个对象,一定要当成对象来用。 

对象就有键,有值。 

键:就是你要监控的那个家伙,比如说$route,这个就是要监控路由的变化。或者是     data中的某个变量。 

值可以是函数:就是当你监控的家伙变化时,需要执行的函数,这个函数有两个形     参,第一个是当前值,第二个是变化后的值。 

值也可以是函数名:不过这个函数名要用单引号来包裹。 

第三种情况厉害了。 

值是包括选项的对象:选项包括有三个。

          第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。

第二个是deep:其值是true或false;确认是否深入监听。(一般监听时是不能监听到对象属性值的变化的,数组的值变化可以听到。)
第三个是immediate:其值是true或false;确认是否以当前的初始值执行handler的函数。

computed

    做筛选功能,与watch的用法相似,也是键值,键就是data里面的数据名称,值是一个函  数,用来操作步骤。

组件的生命周期

beforeCreate

实例初始化之后,this指向创建的实例,不能访问到data、computed、watch、methods上的方法和数据

常用于初始化非响应式变量

created

实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,不能访问到 e l 属 性 , el属性, elref属性内容为空数组

常用于简单的ajax请求,页面的初始化

beforeMount

在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数

mounted

实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问

常用于获取VNode信息和操作,ajax请求

beforeupdate

响应式数据更新时调用,发生在虚拟DOM打补丁之前

适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器

updated

虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作

避免在这个钩子函数中操作数据,可能陷入死循环

beforeDestroy

实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例

常用于销毁定时器、解绑全局事件、销毁插件对象等操作

destroyed

实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>
<body>
    <div id="app">{{a}}</div>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                a: 'vuejs',
            },
            beforeCreate: function() {
                console.log('创建前');
                console.log(this.a);
                console.log(this.$el);
            },
            created: function() {
                console.log('创建之后');
                console.log(this.a);
                console.log(this.$el);
            },
            beforeMount: function() {
                console.log('mount之前');
                console.log(this.a);
                console.log(this.$el);
            },
            mounted: function() {
                console.log('mount之后');
                console.log(this.a);
                console.log(this.$el);
            },
            beforeUpdate: function() {
                console.log('更新之前');
                console.log(this.a);
                console.log(this.$el);
            },
            updated: function() {
                console.log('更新完成');
                console.log(this.a);
                console.log(this.$el);
            },
            beforeDestroy: function() {
                console.log('组件销毁之前');
                console.log(this.a);
                console.log(this.$el);
            },
            destroyed: function() {
                console.log('组件销毁之后');
                console.log(this.a);
                console.log(this.$el);
            },
        })
    </script>
</body>
</html>


beforeCreated: el和data并未初始化 created: 完成data数据的初始化,el没有 beforeMount: 完成了el和data初始化 mounted: 完成挂载

打开命令行在命令行中输入vm.a = ‘change’;查看效果

注意:

created阶段的ajax请求与mounted请求的区别

前者页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态
mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染
完毕,可以用 vm.$nextTick

vue2.0之后主动调用$destroy()不会移除dom节点,作者不推荐直接destroy这种做法,如果实在需要这样用可以在这个生命周期钩子中手动移除dom节点

组件通讯

  • 练习传值

—props emit bus
—vuex slot都可以传值

  • 练习组件传值
    Vue 组件间通信六种方式

props/$emit
e m i t / emit/ emit/on
vuex
a t t r s / attrs/ attrs/listeners
provide/inject
p a r e n t / parent/ parent/children 与 ref

父组件给子组件传值

// 父组件向子组件传递数据
<!--
msg 是在data中(父组件)定义的变量
如果需要从父组件中获取logo的值,就需要使用props['msg'],30行
在props中添加了元素以后,就不需要在data中(子组件)中再添加变量了
-->
<template>
  <div>
    <child  @transferuser="getUser" :msg="msg"></child>  
    <p>用户名为:{{user}}(我是子组件传递给父组件的数据)</p>  
  </div>
</template>
 
<script>
    import child from './child.vue';
    export default {
        components: {
            child,
        },
        data() {
            return {
                user: '',
                msg: '我是父组件传给子组件的信息',
            };
        },
        methods: {
            getUser(msg) {
                this.user = msg;
                console.log(msg);
            },
        },
    };
</script>


    传   父组件用:变量名:"变量值"

    接    在子组件中定义props属性

        props:{

            变量名:变量的类型

        }

    用    在模板里{{变量名}}即可等到传过来的值

  在子组件使用父组件传入的值时,最好复制出一份props的值,通过data或者computed进行赋值。

data赋值与computed赋值的区别:

data赋值:data:{return {aaa: this.aaa}如果是在data中进行赋值,当父组件的aaa值发生改变时,不会在重新赋给子组件中的aaa。

computed赋值:如果想让子组件跟着父组件修改,需要将赋值操作写在computed中。computed:{aaa(){return this.aaa}

子组件给父组件传值

// 子组件向父组件传递数据
<!--
1.@ : 是  v-on的简写
2.子组件主要通过事件传递数据给父组件
3.当input的值发生变化时,将username传递给parent.vue,首先声明了一个setUser,用change事件来调用setUser
4.在setUser中,使用了$emit来遍历transferUser事件,并返回this.username,其中transferuser是一个自定义事件,功能类似一个中转,this.username通过这个事件传递给父组件
-->
<template>
  <div>
      <div>{{msg}}</div>
      <span>用户名</span>
      <input v-model="username" @change='setUser'>向父组件传值</button>
  </div>
</template>
 
<script>
    export default {
        data() {
            return {
                username: '测试',
            };
        },
        props: {
            msg: {
                type: String,
            },
        },
        methods: {
            setUser() {
                this.$emit('transferuser', this.username);
            },
        },
    };
</script>


    传   在子组件定义一个事件如@click="add" 

        然后 在methods中设置
      methods: {

                        add() {

                     用 this.$emit触发在父组件中定义好的自定义事件(例子中的increment)

                     name是子组件要传给父组件的值

                            this.$emit('increment',this.name)  

                        }

             }
    接    在父组件中定义好的子组件的标签上定义

        increment就是自定义事件,子组件就是触发的这个事件

        incrementTotal是触发自定义事件后发生的函数方法

            <Zi @increment="incrementTotal"></Zi>

            

             methods: {

                   incrementTotal (name) {

                  name就是子组件传过来的值,只要将他赋值给data里的变量,就可以在模板使用了

                            console.log(name)

                        }

                   }
    用    在模板里{{变量名}}即可等到传过来的值

非父子通信

    简单情况下我们可以通过使用一个空的Vue实例作为中央事件总线
 在main.js文件夹下建一个vue空实例

        let bus = new Vue()

        Vue.prototype.bus = bus

        

        在一个组件中定义this.bus.$emit('toChangeTitle','从首页来')

            toChangeTitle自定义事件名称,后面是要传的值

        

        在另一个组件中的接收

        mounted () {

                    this.bus.$on('toChangeTitle', function (title) {

                    toChangeTitle //前一个组件定义的自定义事件名

                    title //值 把他赋值给data里的变量就可以在模板中使用了

                             console.log(title)

                     })

          }

dom操作

    vue提供的ref属性以及this.$refs即可实现

    

    

    $refs

首先你的给子组件做标记。demo :

然后在父组件中,通过this.$refs.one就可以访问了这个自组件了,包括访问自组件的data里面的数据,调用它的函数

2)$children

    他返回的是一个组件集合,如果你能清楚的知道子组件的顺序,你也可以使用下标来操作;

1 2 3

for(let i=0;i<this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …nsole.log(this.children[i].msg);输出子组件的msg数据; }

     2)$parent 与$children相似

route 和 router 的区别是什么?

route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
router是“路由实例对象”,包括了路由的跳转方法(push、replace),钩子函数等。

路由

https://juejin.im/post/5b10b46df265da6e2a08a724

vue-router 有哪些钩子函数
官方文档:vue-router钩子函数

全局前置守卫 router.beforeEach
全局解析守卫 router.beforeResolve
全局后置钩子 router.afterEach
路由独享的守卫 beforeEnter
组件内的守卫 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
前端路由简介以及vue-router实现原理

vue-router是专门针对于vue提供单页面路由创建的插件

什么单页面应用?

只有一个页面的应用,但是可以有多个路由地址。正常情况下只要是a链接,点击后都会向服务端发起请求

而单页面应用,

只有在第一次访问的时候,或者强制刷新的时候会向服务端发起请求,其他情况则不会

这是由于单页面路由利用前端页面的几个特性

1,hash

hash可以改变url地址不会向后端发出请求,而且留有历史纪录,通过hashchang事件可以监听hash的改变

2,history

html5针对history api新增了,pushState, replaceState 方法进行url地址的改变,并且不会向服务端发起请求

新增了popstate事件监听url通过历史纪录,pushstate,replaceState方法改变url的监听

单页面应用的特点

改变url地址,

不会像后端发起请求,并且可以重新渲染页面,达到页面异步更新的效果,

而且会留有历史纪录

在vue中结合history,hash实现了路由跳转的封装,封装成了统一的跳转方法,统一的监听处理,

同vue实例中mode选型可以对两种模式进行切换

什么是路由?

路由的概念本身是后端,后端通过定义路由,指定渲染的页面,浏览器通过url地址访问,服务端接收到请求,给客户端返回需要渲染的内容

一个url地址

vue-router如何使用

1,下载vue-router并且引入 import VueRouter from ‘vue-router’

2,注册vue-router vue.use(VueRouter)

3, 实例化vue-router new VueRouter(配置)

4, 对实例进行配置

配置选项:

   {

     mode: 'hash', // hash || history

     router: [

       {

         path: '', //路由地址 /user

         compoent: '',  路由对应需要渲染的组件,渲染到router-view对应的位置

         name: '', 指定路由名称

         meta: {}, 路由的其他配置参数可以是如何数据

         redirect: '', 重定向

         children: [

           {

             path: 'home'   // /user/home

           },

           {

             path: '/home'  // /home

           }

         ], //对应的子路由

       }

     ],  // 所有路由列表, 每一项是一个路由规则

   }

5, router-view 指定路由对应渲染的位置

6, 将router实例挂载到vue根实例上,在组件中就可以使用$router访问到router实例了

7,路由的跳转控制

使用组件router-link

使用js方法 $router.push()

          $router.replace()

          back() 

          go() ....

8, 路由的拦截

r o u t e r 和 router和 routerroute的关系

$route为当前router跳转对象里面可以获取name、path、query、params等

r o u t e r 为 V u e R o u t e r 实 例 , 想 要 导 航 到 不 同 U R L , 则 使 用 router为VueRouter实例,想要导航到不同URL,则使用 routerVueRouterURL使router.push方法等

中的to 和 :to 的区别

to是指直接跳转页面

:to是指跳转时候传参go

路由传参

 params传参   <router-link :to="{name:'go',params:{'cc':'this is cc'}}">

 query传参   <router-link :to="{name:'go',query:{'cc':'this is cc'}}">

1、用法上的

刚才已经说了,query要用path或者name都可以引入,params要只用用name来引入,接收参数都是类似的,分别是this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name和this. route.query.namethis.route.params.name。

注意接收参数的时候,已经是 r o u t e 而 不 是 route而不是 routerouter了哦!!

2、展示上的

query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示

3.调用方面

params一旦传参就必须调用,e而query,定以后可调可不调用

因为params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系

4.使用场景

params:/router1/:id ,/router1/123,/router1/789 ,这里的id叫做params

query:/router1?id=123 ,/router1?id=456 ,这里的id叫做query。

响应路由参数的变化

提醒一下,当使用路由参数时,例如从 /user/foo 导航到 user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。

复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch(监测变化) $route 对象:

命名视图

有时同时(候想同级)展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置(带上 s):

const router = new VueRouter({ routes: [ { path: ‘/’, components: { default: Foo, a: Bar, b: Baz } } ] })

重定向


重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b:

const router = new VueRouter({   routes: [     { path: '/a', redirect: '/b' }   ] })

重定向的目标也可以是一个命名的路由:

const router = new VueRouter({   routes: [     { path: '/a', redirect: { name: 'foo' }}   ] })

甚至是一个方法,动态返回重定向目标:

const router = new VueRouter({   routes: [     { path: '/a', redirect: to => {       // 方法接收 目标路由 作为参数       // return 重定向的 字符串路径/路径对象     }}   ] })

别名

『重定向』的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,那么『别名』又是什么呢?

/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。

上面对应的路由配置为:

const router = new VueRouter({ routes: [ { path: ‘/a’, component: A, alias: ‘/b’ } ] })

『别名』的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。

导航钩子

vue-router 提供的导航钩子主要用来拦截导航,让它完成跳转或取消。有多种方式可以在路由导航发生时执行钩子:全局的, 单个路由独享的, 或者组件级的。

全局钩子
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => {     // do something      next(); }); router.afterEach((to, from, next) => {     console.log(to.path); });

每个钩子方法接收三个参数:

to: Route : 即将要进入的目标 [路由对象]
from: Route : 当前导航正要离开的路由
next: Function : 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next方法的调用参数。
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是confirmed (确认的)。

next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from路由对应的地址。

next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。

确保要调用 next方法,否则钩子就不会被 resolved。

组件内的钩子
你可以在路由组件内直接定义以下路由导航钩子:

beforeRouteEnter beforeRouteUpdate (2.2 新增) beforeRouteLeave

const Foo = {   template: `...`,   beforeRouteEnter (to, from, next) {     // 在渲染该组件的对应路由被 confirm 前调用     // 不!能!获取组件实例 `this`     // 因为当钩子执行前,组件实例还没被创建   },   beforeRouteUpdate (to, from, next) {     // 在当前路由改变,但是该组件被复用时调用     // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,     // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。     // 可以访问组件实例 `this`   },   beforeRouteLeave (to, from, next) {     // 导航离开该组件的对应路由时调用     // 可以访问组件实例 `this`   } }

beforeRouteEnter 钩子 不能 访问 this,因为钩子在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) {   next(vm => {     // 通过 `vm` 访问组件实例   }) }

你可以 在 beforeRouteLeave 中直接访问 this。这个 leave 钩子通常用来禁止用户在还未保存修改前突然离开。可以通过 next(false) 来取消导航。

vuex

vue

 原理:

vuex的方案是,在vue中构建一个用于存储state、定义操作state方法的仓库(即store)。通过在多个(不一定是全部)组件中引用需要的state、调用“操作state的方法”来实现对给共享变量的处理。且由于各个组件对state是引用的,单个组件改变了某个state后,其他组件可以实时的响应变化。

使用

1.下包

    cnpm install --save-dev vuex

2.在项目src目录下创建vuex文件夹,再里创建store.js文件

3.在store.js中

    引入vue和vuex

    import Vue from 'vue'

    mport Vuex from 'vuex'

    在入口文件引入vuex并将store添加到根结点上

4.store.js中的基本结构是
 import Vue from 'vue'

        mport Vuex from 'vuex'

        

        Vue.use(Vuex)

        

        const state = {   //状态 在视图里面渲染的基本都放在state里

                list:[],

                num:0

            //存放共享组件

        }

        const getters = { //计算过滤操作

            state中的变量:(state)=>{

                return  state.变量名+一些列的操作

            }

        }

        const mutation = {  //同步改变状态

            add(state){

                state.num++

            } 

            //可以放一些改变state的方法

        }

        const actions ={    //异步改变状态 在视图中调用actions里的方法一般使用  

                                        this,$store.dispatch('方法名')

            方法名(context){    //这里的context是一个上下文对象  相当于当前的store    也可以直接                 

                                            使用{commit}

                context.commit('调用mutation里的方法',自由参数)

            }

        }

        

        

        export default new Vuex.store({

            state,

            mutations,

            actions,

            getters,

            

        })

    视图应用

        如果想把state里的数据映射在视图中,如liste:[]需要以下操作

        第一种:可以直接在组件中{{this.$store.state.list}}  //注意list是个数组需要循环

        第二种 可以在视图中引入mapState方法  
 import  {mapState}  from 'Vuex'

                    然后在视图计算属性中

                    computed:{

                        ...mapState(['list'])    //es6的扩展符

                    }

                    然后在组件中直接使用    {{list}} //注意list是个数组需要循环

                    

               

             如果想把mutation里的方法想应用在视图中,如add需要以下操作

            第一种:可以直接在组件中事件的函数中“this.$store.commit("add",自由参)”  

            第二种 可以在视图中引入mapMutation方法  

                    import  {mapMutation}  from 'Vuex'

                然后在视图的方法中

                methods:{

                    ...mapMutation(['add'])

                }

                可以直接在组件中事件的函数中"add",自由参

            actions的应用与mutation类似

           getters的应用就是把state引进修改后return出去就好
vuex与全局变量的区别

    vuex响应vue的规则  全局变量

vuex实现的作用:数据共享机制

通过统一的数据中心store维护状态数据,每个组件进行更新的时候,通知数据中心 store。再由stroe将共享的状态,触发每一个调用它的组件的更新。

vuex的工作流程

1.在vue组件里面,通过dispatch来触发actions提交修改数据的操作。

2.然后再通过actions的commit来触发mutations来修改数据。

3.mutations接收到commit的请求,就会自动通过Mutate来修改state(数据中心里面的数据状态)里面的数据。

4.最后由store触发每一个调用它的组件的更新

vuex

什么是状态?

当前样子,可以发生变化,开始的状态,结束的状态。

什么是状态管理?

让状态以一定形式定义,一定的形式改变,一定的形式获取,提供一个规则

Vuex 是什么?

是专门针对vue提供的状态管理模式。

它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能

为什么要用vuex?

为了更好的管理状态,在之前组件内部状态的应用中发现,每个组件的状态都是独立的,如果存在好多组件公用的状态通讯起来比较麻烦

vuex的出现,他是将所有数据状态集中式存储管理,变成了一个,在组件中以相应的规则去读取改变。

有什么能够替代vuex,但是为什么不用?

可以使用redux或者将数据定义在vue根实例中,或者定义全局变量

redux:他并不是针对vue专门做处理的,无法同步状态和视图之间的转换

vue根实例:因为vue根实例的定义是整个应用程序,而不是数据管理

全局变量:var store = {}, 没有规则,无法同步状态和视图之间的转换

vuex:专门针对vue开发的一套以集中式的存储管理整个状态树,并且以对应的规则进行数据的管理,而且还兼容vue的数据检测

vuex的核心概念

state: 唯一数据源, 定义在store中的state选项,在组件中可以通过this.$store.state读取,一半都写在计算属性中,可以通过mapState()函数生成计算属性

getters:相当于组件中的计算属性, 定义在store中getters选项中,在组件中通过$store.getters获取,一半都写在计算属性中,可以通过mapGetters()函数生成计算属性

getters: {

计算属性名称 (state, getters) => {

return 返回值

}

}

mutation: 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,

并且它会接受 state 作为第一个参数, 其他参数为第二个, 通过commit可以执行他

注意:Mutation 必须是同步函数

因为mutation中除了改变state之外还将state改变的过程快照记录了下来,如果在mutation中写异步逻辑的话就无法记录快照了

actions: 用来提交mutations,可以处理异步逻辑,但是不能直接修改state,只能通过commit(‘mutation’)的形式改变state,actions函数接收一个context对象(类似于store实例)

1,webpack打包的配置,常见的loaders和plugins?

2,webpack的基本配置有哪些?

Entry 配置模块的入口;

Output 配置如何输出最终想要的代码;

Module 配置处理模块的规则;

Resolve 配置寻找模块的规则;

Plugins 配置扩展插件;

DevServer 配置 DevServer;

3,webpack 打包按需加载?

在 webpack 的构建环境中,要按需加载代码模块很简单,遵循 ES 标准的动态加载语法 dynamic-import 来编写代码即可,webpack 会自动处理使用该语法编写的模块:

需要我们在 webpack 配置中添加一个 output.chunkFilename 的配置:

output: {

path: path.resolve(__dirname, ‘dist’),

filename: ‘[name].[hash:8].js’,

chunkFilename: ‘[name].[hash:8].js’ // 指定分离出来的代码文件的名称

}

3,简单介绍下webpack的工作原理?

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;

开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;

确定入口:根据配置中的 entry 找出所有的入口文件;

编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;

完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;

输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;

输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

https://whjin.github.io/full-stack-development/posts/工作原理概括.html

4,webpack配置开发环境和生产环境的区别?

日常的前端开发工作中,一般都会有两套构建环境:一套开发时使用,构建结果用于本地开发调试,不进行代码压缩,打印 debug 信息,包含 sourcemap 文件;另外一套构建后的结果是直接应用于线上的,即代码都是压缩后,运行时不打印 debug 信息,静态文件不包括 sourcemap 的。有的时候可能还需要多一套测试环境,在运行时直接进行请求 mock 等工作。

webpack 4.x版本在webpack配置中有mode选项可以直接配置production 或 development

webpack 3.x 一般是通过node命令传递环境变量,来控制不同环境下的构建行为

如:

{

“scripts”: {

"build": "NODE_ENV=production webpack",

"dev": "NODE_ENV=development webpack-dev-server"

}

}

然后在 webpack.config.js 文件中可以通过 process.env.NODE_ENV 来获取命令传入的环境变量:

本地开发跨域问题

在本地开发请求后端服务器接口的时候,都不可避免的会遇到跨域的问题。解决方法可以通过加一个node中间层或者nginx做反向代理。但是如果是用vue-cli搭建的项目,vue-cli在config中自带了一个proxyTable属性,可以配置这个属性解决跨域的问题。

// config/index.js
module.exports = {
// ... 
    dev: {
	proxyTable: { 
	    '/api': { // 遇到/api的接口都会走此代理,因此在调用接口时,需要在url中增加/api标识
		target: 'http://jsonplaceholder.typicode.com', // 真实的地址
		changeOrigin: true, // 是否启用跨域
		pathRewrite: {
		    '^/api': '' // 将接口中的/api替换成''
		}
	    }
        }
    }
}

以上代码会将 /api/posts/1请求代理到 http://jsonplaceholder.typicode.com/posts/1。

如果不想在每一个接口中都手动增加/api标识,可以更改axios的默认配置axios.defaults.baseURL = ‘/api’,这样,axios会自动帮我们在url上加上/api的前缀。

需要特别注意的是,更改完配置后需要重启server才会生效。

深浅拷贝

  • 练习深浅拷贝

深拷贝数组或对象
对象或数组的简单赋值,修改新值也会改变原值。这时我们需要获取原值的深拷贝对象。

对于对象,可以通过newObj = JSON.parse(JSON.stringfy(obj))实现。

对于数组,可以通过 newArr = […arr]或者newArr = arr.slice(0)来实现。

props单向绑定

vue中的props是单向绑定的,父组件的属性变化时会传递给子组件,子组件内部不应改变props的值,否则控制台会给出警告。

但如果props的类型为数组或者对象时,在子组件内部改变props的值控制台不会警告。因为数组或对象是地址引用,vue不会检测到props发生改变。所以有的情况需要在子组件内部改变父组件的值,可以将属性定义为数组或者对象类型传入。

但官方不建议在子组件内改变父组件的值,因为这违反了vue中props单向绑定的思想。

给对象赋值

  • 练习赋值

由1可以引申出,地址引用类型的数据,例如对象obj ={a:1},如果想要修改obj中的a属性,通过obj.a = 2这样赋值,页面不会更新,需使用vue.set方法更改才会起作用, Vue.set(this,obj,a,2) 或者 this.$set(obj,‘a’,2);

同样,如果要给obj增加一个新属性,如果该属性未在data中声明,页面也不会刷新。也就是vue文档中声明的“Vue 不能检测到对象属性的添加或删除”,同样需要使用vue.set 或者this.$set方法进行赋值才好使。

组件里面, data必须是一个函数

类比引用数据类型 Object是引用数据类型, 每个组件的data 都是内存的同一个地址,一个数据改变了其他也改变了;

那么用什么方法可以使每个组件的data相互独立,不受影响呢?

当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

vue中$set的使用场景

  • 练习set

场景1:
通过数组的下标去修改数组的值,数据已经被修改了,但是不触发updated函数,视图不更新,

export default {
    data () {
        return {
            items: ['a', 'b', 'c']
        };
    },
    updated () {
        console.log('数据更新', this.items[0]);
    },
    methods: {
        changeItem1 () {
            this.items[0] = 'x';
            console.log(111, this.items[0]);
        },
        changeItem2 () {
            this.$set(this.items, 0, 'x');
            console.log(222, this.items[0]);
        },
    }
};


执行changeItem1, 控制台打印 111 ‘x’, 没有触发updated,视图不更新 执行changeItem2, 控制台打印 222 ‘x’, 数据更新 ‘x’; 触发updated,视图更新
场景2: vue中检测不到对象属性的添加和删除

data() {
     userProfile: {
        name: '小明',
    }
}

想要给userProfile加一个age属性

addProperty () {
     this.userProfile.age = '12';
     console.log(555, this.userProfile);
}


执行addProperty函数时,打印如下

555 { name: '小明', age: '12'}


但是没有触发updated, 视图未更新 改成下面这种

addProperty () {
      this.$set(this.userProfile, 'age', '12');
      console.log(666, this.userProfile);
 }


再次执行, 数据发生变化, 触发updated, 视图更新;

有时你想向已有对象上添加多个属性,例如使用 Object.assign() 或 _.extend() 方法来添加属性。但是,添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让它包含原对象的属性和新的属性:

// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })


这是vue中很典型的一个问题,使用的时候一定要注意!

简单的解释一下原理:
vue在创建实例的时候把data深度遍历所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。让 Vue 追踪依赖,在属性被访问和修改时通知变化。所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

当你在对象上新加了一个属性newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制(因为是在初始化之后添加的),vue.$set是能让vue知道你添加了属性, 它会给你做处理

watch、methods 和 计算属性的区别

watch 为了监听某个响应数据的变化。计算属性是自动监听依赖值的变化,从而动态返回内容,主要目的是简化模板内的复杂运算。所以区别来源于用法,只是需要动态值,那就用计算属性;需要知道值的改变后执行业务逻辑,才用 watch。
methods是一个方法,它可以接受参数,而computed 不能,computed 是可以缓存的,methods 不会。computed 可以依赖其他 computed,甚至是其他组件的 data。

methods/computed/watch

methods VS computed
我们可以将同一个函数定义为methods或者computed,用这两种方式,得到的结果是相同的,不同的是computed是基于它们的依赖进行缓存的,计算属性只有在它相关的依赖发生改变时才重新求值;

适用场景:
重新计算开销很大的话,选computed; 不希望有缓存的选methods

computed vs watch
watch 有新旧值两个参数, 计算属性没有,但是计算属性可以从setter获得新值

关于computed
对于计算属性要特别说明一点: vue的计算属性computed默认只有getter,需要使用getter的时候需要自己加一个setter

export default {
    data () {
        return {
            firstName: '张',
            lastName: '三',
        };
    },
    computed: {
        fullName() {
              return this.firstName + ' ' + this.lastName
        },
    },
    methods: {
        changeFullName () {
            this.fullName = '李 四';
        }
    },
};
 
其中computed里的代码完整写法是  
 
computed: {
   fullName: {
        // getter
        get: function () {
          return this.firstName + ' ' + this.lastName
        },
   }    
},


执行 changeFullName 发现报错[Vue warn]: Computed property “fullame” was assigned to but it has no setter.

我们需要给计算属性fullName添加一个setter

computed: {
   fullName: {
        // getter
        get: function () {
          return this.firstName + ' ' + this.lastName
        },
        // setter
        set: function (newValue) {
          var names = newValue.split(' ')
          this.firstName = names[0]
          this.lastName = names[names.length - 1]
        }
  }    
},


生命周期函数/methods/watch里面不应该使用箭头函数

es6的箭头函数的出现,是我们可以用更少的代码实现功能,但是应该注意箭头函数和普通函数的最大区别是this的指向问题: 箭头函数的this指向函数所在的所用域,普通函数的this指向函数的调用者;

官方文档中特别提醒中已经指出这一点:

vue中生命周期函数, methods, watch 自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味着 你不能使用箭头函数来定义一个生命周期方法, 这是因为箭头函数绑定了父上下文,因此 this 与你期待的 Vue 实例不同

var let const区别,作用域区别

数据结构有哪些

keep-alive实现重新渲染效果

浮动的面试题

定位的面试题

布局的面试题

http的面试题

vue的优点

低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。

独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。

可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

生命周期相关面试题

总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。

创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el还没有。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法。

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

(1)、什么是vue生命周期

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

(2)、vue生命周期的作用是什么

答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

(3)、vue生命周期总共有几个阶段

答:可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后

(4)、第一次页面加载会触发哪几个钩子

答:第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

(5)、DOM 渲染在 哪个周期中就已经完成

答:DOM 渲染在 mounted 中就已经完成了。

(6)、简单描述每个周期具体适合哪些场景

答:生命周期钩子的一些使用方法:

beforecreate : 可以在这加个loading事件,在加载实例时触发

created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用

mounted : 挂载元素,获取到DOM节点

updated : 如果对数据统一处理,在这里写上相应函数

beforeDestroy : 可以做一个确认停止事件的确认框

nextTick : 更新数据后立即操作dom

vue-loader是什么?使用它的用途有哪些?

解析.vue文件的一个加载器。

用途:js可以写es6、style样式可以scss或less、template可以加jade等

VNode是什么?虚拟 DOM是什么?

Vue在 页面上渲染的节点,及其子节点称为“虚拟节点 (Virtual Node)”,简写为“VNode”。“虚拟 DOM”是由 Vue 组件树建立起来的整个 VNode 树的称呼。

vue数据双向绑定原理,及如何实现

假设有一个输入框组件,用户输入时,同步父组件页面中的数据

具体思路:父组件通过 props 传值给子组件,子组件通过 $emit 来通知父组件修改相应的props值,具体实现如下:

import Vue from 'vue'  
const component = {  
  props: ['value'],  
  template: `  
    <div>  
      <input type="text" @input="handleInput" :value="value">  
    </div>  
  `,  
  data () {  
    return {  
    }  
  },  
  methods: {  
    handleInput (e) {  
      this.$emit('input', e.target.value)  
    }  
  } 
}  
new Vue({  
  components: {  
    CompOne: component  
  },  
  el: '#root',  
  template: `  
    <div>  
      <comp-one :value1="value" @input="value = arguments[0]"></comp-one>  
    </div>  
  `,  
  data () {  
    return {  
      value: '123'  
    }  
  }  
}) 

可以看到,当输入数据时,父子组件中的数据是同步改变的:

我们在父组件中做了两件事,一是给子组件传入props,二是监听input事件并同步自己的value属性。那么这两步操作能否再精简一下呢?答案是可以的,你只需要修改父组件:

template: `  
    <div>  
      <!--<comp-one :value1="value" @input="value = arguments[0]"></comp-one>-->  
      <comp-one v-model="value"></comp-one>  
    </div>  
  ` 

v-model 实际上会帮我们完成上面的两步操作。

vue中如何监控某个属性值的变化

比如现在需要监控data中,obj.a 的变化。Vue中监控对象属性的变化你可以这样:

watch: {  
      obj: {  
      handler (newValue, oldValue) {  
        console.log('obj changed')  
      },  
      deep: true  
    }  
  } 
deep属性表示深层遍历,但是这么写会监控obj的所有属性变化,并不是我们想要的效果,所以做点修改:

watch: {  
   'obj.a': {  
      handler (newName, oldName) {  
        console.log('obj.a changed')  
      }  
   }  
  } 
还有一种方法,可以通过computed 来实现,只需要:

computed: {  
    a1 () {  
      return this.obj.a  
    }  
} 
利用计算属性的特性来实现,当依赖改变时,便会重新计算一个新值。

前端调bug工具

如何区分数据类型

null和undefined区别


vue中怎么重置data
使用Object.assign(),vm. d a t a 可 以 获 取 当 前 状 态 下 的 d a t a , v m . data可以获取当前状态下的data,vm. datadatavm.options.data可以获取到组件初始化状态下的data。

Object.assign(this. d a t a , t h i s . data, this. data,this.options.data())
组件中写 name 选项有什么作用?
项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
DOM 做递归组件时需要调用自身 name
vue-devtools 调试工具里显示的组见名称是由vue中组件name决定的


描述下 vue 从初始化页面–修改数据–刷新页面 UI 的过程?
当 Vue 进入初始化阶段时,一方面 Vue 会遍历 data 中的属性,并用 Object.defineProperty 将它转化成 getter/setter 的形式,实现数据劫持(暂不谈 Vue3.0 的 Proxy);另一方面,Vue 的指令编译器 Compiler 对元素节点的各个指令进行解析,初始化视图,并订阅 Watcher 来更新试图,此时 Watcher 会将自己添加到消息订阅器 Dep 中,此时初始化完毕。
当数据发生变化时,触发 Observer 中 setter 方法,立即调用 Dep.notify(),Dep 这个数组开始遍历所有的订阅者,并调用其 update 方法,Vue 内部再通过 diff 算法,patch 相应的更新完成对订阅者视图的改变。
--------------------------------------------------------
组件中写 name 选项有什么作用?
项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
DOM 做递归组件时需要调用自身 name
vue-devtools 调试工具里显示的组见名称是由vue中组件name决定的


网页从输入网址到渲染完成经历了哪些过程
大致可以分为如下7步:

输入网址;
发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
与web服务器建立TCP连接;
浏览器向web服务器发送http请求;
web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
浏览器下载web服务器返回的数据及解析html源文件;
生成DOM树,解析css和js,渲染页面,直至显示完成;

前端如何优化网站性能?

  1. 减少 HTTP 请求数量

在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。

CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数。
合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。
采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。

  1. 控制资源文件加载优先级

浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应链接内容,为了***时间展示页面给用户,就需要将 CSS 提前加载,不要受 JS 加载影响。

一般情况下都是 CSS 在头部,JS 在底部。

  1. 利用浏览器缓存

浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。

  1. 减少重排(Reflow)

基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的 visibility 属性,这也是 Reflow 低效的原因。如果 Reflow 的过于频繁,CPU 使用率就会急剧上升。

减少 Reflow,如果需要在 DOM 操作时添加样式,尽量使用 增加 class 属性,而不是通过 style 操作样式。

减少 DOM 操作
图标使用 IconFont 替换

如何优化SPA应用的首屏加载速度慢的问题?
将公用的JS库通过script标签外部引入,减小app.bundel的大小,让浏览器并行下载资源文件,提高下载速度;
在配置 路由时,页面和组件使用懒加载的方式引入,进一步缩小 app.bundel 的体积,在调用某个组件时再加载对应的js文件;
加一个首屏 loading 图,提升用户体验;

delete和Vue.delete删除数组的区别
delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。

Vue.delete直接删除了数组 改变了数组的键值。 

var a=[1,2,3,4]  
   var b=[1,2,3,4]  
   delete a[1]  
   console.log(a)  
   this.$delete(b,1)  
   console.log(b) 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值