前端面试题—vue部分详解

vue

基本概念区分

  • 单页面应用:在一个页面跳来跳去,不重新加载页面
  • vue 特点:渐进式 框架 双向数据绑定
    • 双向数据绑定:视图改变 数据自动更新;数据更新 视图自动改变
    • 渐进式:vue vue-router路由 vuex axios
    • 框架:自己写的代码被框架调用(库:自己调用库的代码)
  • 声明式

安装vue

cmd命令

npm i vue

yarn add vue

vue核心实现方法

var obj={}
Object.defineProperty(obj,'name',{
     value:'xhufeng',
     configurable:true,//是否可删
     writable:true,//是否可写
     enumerable:true,//是否可枚举(循环)
     set(val){
        //只要外界给name赋值,就会触发该函数
        //形参val就是外界赋予的值
     },
     get(){
        return 123
     }
  })
复制代码

vue指令

指令都是行内属性 v-model放在input、textarea、select>option上的,实现双向数据绑定 v-text 展示对应的文本 v-once 对应的标签只渲染一次 v-show=布尔 是否能显示,true能显示,false不能显示(存在隐式转化) v-html 把值中的标签渲染出来

v-for

循环显示元素 可以循环数组、对象、数字、字符串 最好加:key='a+i' v-for='item in ary'

v-bind

用于绑定行内属性 简写成:

v-if

控制是否渲染该元素 值是true,则渲染该元素;false则不渲染 与v-else v-else-if连着使用 可以使用template标签,就不会出现多余标签

<body>
    <div id="app">
        <h1>{{name}}</h1>
        <button @click='flag=!flag'>按钮</button>
        <h2 v-show='flag'>hello</h2>
        <h2 v-show='!flag'>world</h2>
        
        <button @click='n=1'>1</button>
        <button @click='n=2'>2</button>
        <button @click='n=3'>3</button>
        <h3 v-if='n===1'>hello</h3>
        <h3 v-else-if="n===2">hahaha</h3>
        <h3 v-else>world</h3>
    </div>
</body>

</html>
<script src="./node/node_modules/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            name: "珠峰",
            flag:true,
            n:1
        },
        methods: {
            fn() {

            }
        }
    })
</script>
复制代码
v-clock

需要配合css使用:解决小胡子显示问题

v-pre

跳过有这个指令的标签及其子元素的编译,按照原生代码编译

vue对象

data中的属性最终都添加到了实例上 属性需要有get set,才能触发视图更新

     let vm = new Vue({
         el: '#app',
         data: {
             name: '刘琪',
             age:21,
             q:'<h1>haha</h1>',
             obj:{
                 a:123,//对于对象来说,新增一个属性不会触发视图更新,只有改变属性时才会触发视图更新
                 b:undefined,
             }
         }
     }).$mount('#app')
     //处理方式
     //1.正常写全要用到的属性;先预留要用到的属性
     //2.整个对象的重新赋值
     //3.$set()方法
     vm.$set(vm.obj,'c','456')
     //4.增加一个无关变量t,每次修改完数据之后;重置t就可以了
复制代码

vue数组

    let vm = new Vue({
        el: '#app',
        data: {
            ary: [1, 2, 3, 4]
        }
    })
    vm.ary.length--;
    //能改变原有数组,但不能触发视图更新,只有数组原型上的变异方法可以触发更新
    //数组变异方法:pop shift unshift push reverse splice sort
复制代码

vue 事件

<body>
    <div id="app">
        {{ary}}
        <button @click='fn'>按钮1</button>
        <button @click='fn(name,$event)'>按钮2</button>
        <!-- $event是固定写法,代表传参事件对象 -->
    </div>
</body>

</html>
<script src="./node/node_modules/vue/dist/vue.js"></script>
<script>
    //事件绑定,用v-on:事件类型=‘函数’  或者  @事件类型=‘函数’
    //函数一般是在methods中定义的
    //对应的函数一般不带小括号,默认传参事件对象e
    //当我们需要传参时,需要加小括号,小括号里写需要传的参数;当只有小括号没有传参时,为undefined
    //el data methods 都是VUE规定死的属性名 
    let vm = new Vue({
        el: '#app',
        data: {
            ary: [1, 2, 3, 4],
            name:'zhufeng'
        },
        methods: {
            fn: function (val,e) {
                console.log(val,e,this)
            }
        }
    })
    //@kryup.13='fn'在按下回车的时候才会触发该函数
</script>
复制代码

vue过滤器

全局用filter,实例局部使用filters 全局过滤器要放在需要使用的实例的前面

vue计算属性computed

  • 于data同级别
  • 语法同methods一样
  • 计算属性的名字 不能跟 data 或 methods 中的名字重复
  • 完全依赖于函数体中出现的属性名,只在最初加载时和其中属性名改变时运行,并不是像methods中的函数只要页面更新就运行一次
  • 不能传参
  • 异步的无法处理
  • 为了提高性能而存在

vue监听属性

  • 当且仅当监听的属性(例如:name)发生变化时会执行函数
  • 可以处理异步
  • 下面这种写法不能监听引用数据类型的内部变化
 watch:{
            name(newV,oldV){
                clearTimeout(this.timer)
                this.timer=setTimeout(() => {
                    if (newV.length > 5) {
                        this.msg2 = '名字太长'
                    }else{
                        this.msg2 = ''
                    }
                }, 500)
            }
        }
复制代码
  • 深度监听需要用下面这种语法
  • 这种深度监听在有get和set属性时才会触发监听
        watch:{
            obj:{
                handler(){
                    console.log(1111)
                },
                deep:true
             }
        }
复制代码

directives自定义指令

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。

vue动画

transition
  • 把需要实现动画的标签用transition标签包起来
  • 只能对根元素有动效

transition-group
  • tag指定外层包裹元素的tag类型;不写,默认span
  • duration控制vue设置的类名存在的时间

事件修饰符

  • .self只点元素本身时才触发事件
  • .stop阻止冒泡事件
  • .prevent阻止默认事件
  • .once对应函数只触发一次
  • .capture在捕获阶段触发二级绑定事件
  • .passive优先执行默认事件(滚动行为)

表单修饰符

  • .number转化为数字,类似parse转化
  • .trim去字符串前后空格

生命周期

enter image description here

    let vm = new Vue({
        el:'#app',
        // template:'<h1>哈哈哈</h1>',
        data:{
            name:"珠峰"
        },
        // 生命周期钩子函数 就是VUE规定的一些在固定阶段执行的函数
        // 语法上 跟 data和el、methods等 同级
        beforeCreate(){
            // 创造之前
            // 不能获取data和methods里的数据
            console.log('beforeCreate');
            debugger;
        },
        created(){            
           // 能获取data和methods里的数据
           // 一般把ajax请求的发送写到这里
        },
        beforeMount() {},
        mounted(){
           // 在此时DOM已经渲染完成
        },
        beforeUpdate(){
           // 在视图更新时会触发其中函数
           // 函数在视图更新前执行
        },
        updated(){
           // 在视图更新时会触发其中函数
           // 函数在视图更新后执行
           // 不要写会触发视图更新的代码
        },
        beforeDestroy(){},
        destroyed(){}
    })
    vm.$destory();//手动销毁该实例,双向数据绑定没了
复制代码

组件

  • 划分比较明细,复用率比较高
  • 功能性组件 页面级组件
  • 全局组件 局部组件
  • template模板中只能有一个根元素

全局组件的注册

  • 必须写到根组件(根实例)的前面
    //全局组件的定义
    Vue.component('qqq',{
        template:'<i>hello 小聪子</i>'
    })
复制代码
<body>
    <div id="app">
        <h1>{{name}}</h1>
        <aaa></aaa>
        <aaa></aaa>
        <my-name></my-name>
        <!-- 不支持驼峰式命名 -->
        
    </div>
</body>
   <template id='qqq'>
        <div>
            <input type="text" v-model='name'>
            <h1><i>{{name}}</i></h1>
        </div>
    </template>

<script>
    //全局组件的定义
    //使用时只要把组件名当作标签使用即可
    Vue.component('aaa', {
        //没有el属性,有template属性,data是个函数,并且返回一个对象
        //template就是qqq标签要去展示的内容
        //template有且只能有一个根元素
        template: '#qqq',
        data() {
            return {
                name: 'zhufeng'
            }
        },
        created() {
            console.log(this.name)
        }
    })
    Vue.component('myName', {
        template: `<h2>My name is </h2>`,
        data() {
            return {
            }
        },
    })
    let vm = new Vue({
        el: '#app',
        data: {
            name: "珠峰"
        }
    })
</script>
复制代码

局部组件的注册

  • 局部组件只能使用在此之前声明的局部组件作为子组件

<body>
    <div id="app">
        <h1>{{name}}</h1>
        <son></son>

        <parent></parent>
    </div>
</body>

<template id="opp">
    <h2>ninininini</h2>
</template>

<template id="o">
    <h2>小聪子<son></son></h2>
</template>

<script>
    let son = {
        template: '#opp',
        data() {
            return {

            }
        }
    }
    let parent = {
        template: '#o',
        data() {
            return {

            }
        },
        components: {
            son
        }
    }
    let vm = new Vue({
        el: '#app',
        data: {
            name: "珠峰"
        },
        components: {
            son,
            parent: parent
        }
    })
</script>
复制代码

组件的数据传输

父传子

过程

  • 1.通过v-bind绑定属性,把相应的数据传递给子组件
  • 2.子组件通过props接收传进来的数据

注意事项

  • 父传子是单向数据流,不能从子组件修改父组件的数据
  • 但如果是引用数据类型,不修改地址,只改变内容,可以改变
  • props可以是数组,也可以对象
  • props中自定义属性的参数
  • - 1.default:默认值
    复制代码
  • - 2.type:规定此属性的数据类型
    复制代码
  • 可以通过实例this.$parent调用父组件的数据和方法(不推荐)
<body>
    <div id="app">
        <h1>{{name}}</h1>
        <input type="text" v-model='name'>
        <son :name='name'></son>
    </div>
</body>

<template id="o">
    <div>
        <h3>{{name}}</h3>
        <button @click='fn'> 这个按钮点击了{{n}}次</button>
    </div>
</template>

<script>
    let son = {
        template: '#o',
        data() {
            return {
                n: 0
            }
        },
        methods: {
            fn() {
                this.n++
            }
        },
        props:['name']
    }
    let vm = new Vue({
        el: '#app',
        data: {
            name: "珠峰"
        },
        components: {
            son,
        }
    })
</script>
复制代码
子传父

本质上是父组件使用子组件的数据

官方过程

  1. 通过自定义事件触发父组件中的方法
  2. 再由子组件方法的执行通过this.$emit('自定义事件名',this.qqq)传递子组件的数据

也可以在父组件中通过this.$children[i]调用子组件的数据及方法 也可以在父组件中通过this.$refs.son调用子组件的方法

插槽

在template模板中写入<slot></slot>,可显示在使用组件时组件名标签内部内容

具名插槽

在slot标签中的name属性是控制要去显示哪一部分的一个功能 不写时,默认default,全部显示 name对应的的是slot='qqq'的部分

模板中若有与name值对应的元素,则slot标签包含的内容不会显示出来;反之,可以显示

子父组件的mounted

执行顺序

动态组件component

keep-alive

-在没有keep-alive时,component组件是销毁旧的,重新渲染新的 -加上keep-alive后,动态组件有缓存机制,不会销毁旧的

  <keep-alive>
      <component :is='son'></component>
  </keep-alive>

复制代码

vue-router

vue-router是vue的路由插件

基本用法

  • 步骤
  • 1、声明组件
  • 2、编写路由映射表
  • 3、把编辑好的映射表注入到router实例中
  • 4、把router实例注入到根实例中
  • router-link 控制跳转的链接和显示的文字
  • router-view 控制显示的组件内容
  • active-class 控制选中对应路径的类名
  • tag 控制渲染成什么标签
<body>
    <div id="app">
       <router-link to='/home' active-class='current'>首页</router-link>
       <router-link to='/list' tag='div'>列表</router-link>
       <router-view></router-view>
    </div>
</body>

</html>
<template id="home">
    <div>home</div>
</template>
<template id="list">
    <div>list</div>
</template>
<script src="../node/node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script>

    let home = {
        template: '#home',

    }
    let list = {
        template: '#list',

    }

    //路由映射表
    let routes = [{
            path: '/home',
            component: home
        },
        {
            path: '/list',
            component: list
        }
    ]

    let router=new VueRouter({
        routes:routes,
    })
    let vm = new Vue({
        el: '#app',
        data: {
            name: "珠峰"
        },
        router,
    })
</script>
复制代码

传参

  • 提供了两种传参方式
  • 1、query传参(问号传参)
  • 路由映射表不用改动 :to={path:'',query:{}}或者:to={name:'',query:{}}
  • 2、params传参(路径传参)
  • 在映射表中添加 /:变量 的形式; :to={name:'',params:{变量:''}}}

<router-link :to='{path:"/list",query:{id:123,e:name}}' tag='div'>列表</router-link>

重定向redirect

let routes = [
        {
            path:'/',
            redirect:'/son2/222'
        },
        {
            path:'/son1',
            // redirect:'/son2/5555',
            name:'son1',
            component:son1,
            redirect:'/son1/sz',
            children:[
                {
                    path:'/son1/sz',
                    component:sz
                }
            ]
        },
        {
            path:'/son2/:bl1234',
            name:'son2',
            component:son2
        },
        {
            path:'/*',
            redirect:'/son1'
        }
    ]
复制代码

vuex

是一个能方便vue实例及其组件传输数据的插件 方便传输数据,作为公共存储数据的一个库

基本用法

  • 步骤
  • 1、创建一个vuex实例
  • 2、在根组件中注册一下
  • 3、注册后,根组件及其一下的局部或全局组件可使用vuex实例中的数据方法,多个组件使用同一套规则时,我们可以把这套规则单独拎出来写在vuex实例中通用

方法汇总

state

类似vue实例中的data,存储数据 在vue实例中用this.$store.state调用state里的数据 使用...Vuex.mapStore(['count'])将其数据放入computed中

mutations

官方提供的唯一改数据的方法 其中必须是同步函数 通过commit来调用mutations中的函数 其中函数最少有一个参数state,最多两个参数另加val(调用时的传参) 使用...Vuex.mapMutations(['mu_add'])将其函数放入methods中

actions

可以写异步函数,一般多用于触发ajax请求 不能直接用于修改state中的数据,需要通过其中函数默认的第一个实参obj,用obj.commit('mu_')来调用mutations中的函数来修改数据 使用...Vuex.mapActions(['ac_add'])将其函数放入methods中

getters

类似vue实例中的计算属性,存储数据 使用...Vuex.mapGetters(['remove'])将其函数放入computed中

    //1、创造一个vuex实例
    //2、把创造的实例放到根实例中
    //使用this.$store.state
    let son1 = {
        template: `<div>
                <button @click='add'>增加</button>
                <button @click='mu_add(100)'>增加</button>
                <button @click='add2(100)'>2增加</button>
                <h2>{{count}}</h2>
                <h2>{{qqq}}</h2>
            </div>`,
        data() {
            return {

            }
        },
        computed: {
            //两种监听vuex数据的写法
            // myCount(){
            //     return this.$store.state.count
            // }
            ...Vuex.mapState(['count', 'qqq'])
        },
        methods: {
            add() {
                // this.$store.state.count++
                // this.$store.commit('mu_add', 1)
                this.mu_add(10)
            },
            ...Vuex.mapMutations(['mu_add']),
            add2() {
                this.$store.dispatch('ac_add', 22)
                //dispatch 触发的是actions里的函数
                //commit   触发的是mutations里的函数
            }
        }
    }
    let son2 = {
        template: `<div>
                <button @click='remove'>减少</button>
                <h2>{{$store.state.count}}</h2>
            </div>`,
        methods: {
            remove() {
                this.$store.commit('mu_remove', 1)
            }
        },
    }
    let store = new Vuex.Store({
        state: {
            count: 0,
            qqq: 12
        },
        
        mutations: {
            mu_add(state, val = 1) {
                console.log(arguments)
                //第一个实参是默认传的state
                //第二个实参是自己传的参数
                //一共只有一个或两个实参
                state.count += val
            },
            mu_remove(state, val = 1) {
                console.log(arguments)
                //第一个实参是默认传的state
                //第二个实参是自己传的参数
                //一共只有一个或两个实参
                state.count -= val
            }
        },
        actions: {
            ac_add(obj,n) {
                //obj是vuex封装好的一个对象,里边提供了commit方法
                obj.commit('mu_add',n)
                console.log(arguments)
            }
        }
        //mutations中必须是同步函数,actions同步异步都行
        //想要修改state里的数据只能用commit来调用mutations里的函数
    })
    let vm = new Vue({
        el: '#app',
        store,
        data: {
            name: "珠峰"
        },
        components: {
            son1,
            son2
        },
        created() {
            console.log(this)
        },
    })
复制代码

==========================================================

前端小白,第一次发文,欢迎评论指正!

猜你喜欢

转载自juejin.im/post/5c6d4a46f265da2de6610287