Vue的补充内容

一、Vue相关知识

1. 注入

为什么Vue中的配置data,method会提取到vm实例中,这个过程称为注入

  • 目的:

    1. 数据响应式

      Vue2.0通过 Object.defineProperty 方法完成数据响应式; Vue3.0通过 Class Proxy完成数据响应式

    2. 绑定this

      为什么this.data/this.method中的this指向vue的实例

2 虚拟DOM树

提高渲染效率,vue把模板编译成虚拟DOM树(js对象构成),再生成真实DOM树

当修改元素后,会将前后虚拟DOM树进行对比(虚拟DOM每一次全新生成),最大减少对真实DOM的操作

模板的来源:根标签中的outerHTML<template>标签中、render函数,优先级逐渐提升

{
    render(h): {
        return h("h1", val)
    }
}

3 挂载

内容放置到哪个元素上面的过程

挂载方式:el属性、通过vm.$mount('')延迟挂载

4 完整流程

在这里插入图片描述

二、特殊属性

1. watch属性

能够监视data的动态变化

const vm = new Vue({
    el: '#app',
    data: {
        a: 1
    },
    watch: {
        a: {
            handler(newValue, oldValue) {
                console.log("a被修改了", newValue, oldValue)
            }
        }
    }
})

在这里插入图片描述
第二种写法,在创建实例后添加监听属性

vm.$watch('a', {
   handler(newValue, oldValue) {
        console.log("a被修改了", newValue, oldValue)
    }
})
  • 深度watch

当存在多层级的属性的时候:

 data: {
   members: {
        a: 1,
        b: 1
    }
},

此时想要监听members内部的a, b属性,可以写下面的代码:

watch: {
    'members.a': {
        handler(newValue, oldValue) {
            console.log("a被修改了", newValue, oldValue)
        }
    },
    'members.b': {
        handler(newValue, oldValue) {
            console.log("b被修改了", newValue, oldValue)
        }
    }
}

但是当members中的属性很多的时候,书写起来就不方便,因此有了深度watch,通过监听members,进而监听内部的属性值

watch: {
    members: {
        deep: true,
        handler() {
            console.log("members 被修改了")
        }
    }
}
  1. 当计算属性和watch同时能实现的时候,使用计算属性更容易;但是当涉及异步任务的时候应该使用watch
  2. 所有Vue管理的函数,最好写成普通函数,这样this指向的是vm或组件实例
    而使用如 定时器的回调函数,ajax回调函数的时候,应该使用箭头函数,这样this的执行会向外查找到Vue的实例,进而拿到Vue的对象。

2. key的作用

最重要的特殊属性:key

该属性可以干预diff算法,影响虚拟DOM节点的比较;在同一层级,key值相同的节点进行对比,key值不同的重新生成
在这里插入图片描述
在这里插入图片描述

key是虚拟DOM的标识
当插入数据的时候打乱顺序,使用index作为key在虚拟DOM对比算法的过程中可能因为复用虚拟dom节点的问题导致复用错误的信息;如果比较情况下内容相同,会直接复用旧DOM中的值。

3. 计算属性

{
    el: '#app',
    data: {
        firstName: '',
        lastName: ''
    },
    computed: {
        // fullName() {
        //     return this.firstName + this.lastName 
        // } 
        // 完整写法
        fullName: {
            get() {
                return this.firstName + this.lastName 
            },
            set(val) {
                console.log('设置器...');
                this.firstName = val[0]
                this.lastName = val.substr(1)
            }
        }
    }
}

计算属性和方法的区别:

  1. 计算属性有访问器和设置器,可以对参与计算的属性进行方向操作
  2. 计算属性具有缓存,如果依赖不变,则不会重新计算
  3. 一般建议使用已有data属性计算的属性内容,设置成计算属性而不是方法

4. ref属性

vue中,采用MVVM理念,不需要直接操作DOM

如果需要操作DOM元素的场景,可以使用 ref 进行操作;每一个vue组件实例对象上都有一个$refs属性可以获取元素对象,默认是空对象

其次,组件实例也有$refs属性,类似组件传值,如果父组件需要直接操作子组件的属性,可以借助这个属性完成。

  • this.$nextTick(cb)

参数cb为一个回调函数,保证函数执行在DOM重新渲染完毕继续执行

场景:组件显隐操作,等待组件重新渲染成功后继续执行后续操作

三、 Vue-cli

1. 项目创建

npm install -g @vue/cli   // 第一次安装脚手架
vue create xxx  // 创建一个项目

npm run serve: 项目执行
npm run build: 将vue编译成.html文件

main.js 入口文件

// 引入Vue
import Vue from 'vue';
// 所有组件的父组件
import App from './App.vue'
new Vue({
	// render渲染函数, h表示Vue中的一个createElement函数,用来创建元素
    render: h => h(App)  // 将App组件放入容器, '#app'
}).$mount('#app')

vue中可以通过ref获取到dom元素,用来给标签或子组件注册引用信息(id的替代者)
props组件传值,如果需要约定类型,可以用对象形式表示

props: {
	name: String,
	age: Number,
	sex: String
}

外部传入的值不能直接修改

Vue.use() 可以使用插件

2. 代理服务器

在前端维护代理服务器,用来解决跨域;代理服务器使用node保证node后台和服务器的交互,而XmlHttpRequest是属于浏览器中的内置对象,为了浏览器的安全因此有了跨域,在引入代理服务器后没有浏览器的参与就不涉及跨域了。

module.exports = {
  devServer: {
    proxy: 'http://localhost:4000'
  }
}

只能配置一个代理

第二种:

module.exports = {
  devServer: {
    proxy: {
      '/api': {  // 请求前缀,第一个请求
        target: '<url>',
        pathRewrite: {'^/api': ''}  // 重写请求路径,将前缀去除
        ws: true,
        changeOrigin: true
      },
      '/foo': {  // 第二个请求
        target: '<other_url>'
      }
    }
  }
}

四、组件

1. Html中组件的创建

使用局部组件的方式创建如下代码

<div id="app">
    <button @click="onReverse">测试切换</button>
     <!-- 通过:is 可以实现动态切换组件的效果,数据变化由组件名称决定 -->
     <!-- :props, 用于父组件向子组件数据传递 -->
     <!-- :func 为子组件向父组件传递数据时的方法调用 -->
     <hello :props="props" @func="onFunc"  :is="currentComponent"></hello>
     <other :is="!currentComponent"></other>
     <div>
         <label>我是:</label>
         <span>{{ sonHTML }}</span>
     </div>
 </div>

 <!-- 定义模板template begin -->
 <template id="hello">
     <div>
         用户名: {{ props.name }} <br>
         <a href="www.baidu.com" @click.prevent="onClick(props)">hello world</a>
     </div>
 </template>

 <template id="other">
     <div>其他内容</div>
 </template>
 <!-- 定义模板template end -->
<script>
   // 声明组件 begin
   const hello = {
       template: '#hello',
       props: ['props'],
       methods: {
           onClick(param) {
               this.$emit('func', param.name);
           }
       }
   }

   const other = {
       template: '#other',
   }
   // 声明组件 end

   // 创建实例
   new Vue({
       el: '#app',
       components: {  // 注册组件
           hello: hello,
           other: other
       },
       data: {  // 声明绑定响应式数据
           a: 5,
           props: {
               name: 'zs',
               age: 18
           },
           sonHTML: '',
           currentComponent: 'other'
       },
       methods: {
           onFunc(param) {
               this.sonHTML = param;
           },
           onReverse() {  // 组件切换
               if (this.currentComponent == 'hello') {
                   this.currentComponent = 'other'
               } else {
                   this.currentComponent = 'hello'
               }
           }
       }
   })
</script>

在这里插入图片描述

2. 组件传值

2.1 兄弟组件的传值

vue2中,兄弟组件之间的数据共享使用EventBus

使用步骤:

  • 创建eventBUs.js模块,向外共享一个Vue实例对象
import Vue from 'vue'

export default new Vue()
  • 数据发送方,调用bus.$emit()触发自定义事件
methods: {
    handleSendMsg() {
        bus.$emit('receive', this.sendMsg)
    }
}
  • 数据接收方,调用bus.$on('事件名称','事件处理函数')注册一个自定义事件
created() {
    bus.$on('receive', val => {
        console.log('在HelloWorld组件中接收数据:', val);
        this.testMsg = val
    })
}

3. 动态组件

vue 中提供 <component>标签,实现动态组件的渲染

<component :is="自定义变量表示组件名称"></component>

动态组件每一次切换都会进行销毁,为了避免组件被销毁对组件进行缓存,可以使用keep-alive进行包裹

<keep-alive>
	<component :is="自定义变量表示组件名称"></component>
</keep-alive>

通过 include属性可以控制 keep-alive 缓存哪些组件

或者通过 exclude进行排除,两者不能同时使用

<keep-alive include="Left, Right">
	<component :is="自定义变量表示组件名称"></component>
</keep-alive>

4. 插槽

提供vue开发者灵活封装组件的能力,将不确定、用户指定的部分定义为插槽

每个插槽都应该有一个name属性,如果不指定,默认名称是default

4.1 具名插槽

可以通过name属性进行指定

<template v-slot:left>
	<p>我是一个插槽</p>
</template>
<!--简写形式-->
<template #left>
	<p>我是一个插槽</p>
</template>
<!--组件定义-->
<slot name="left"></slot>

4.2 作用域插槽

插槽中可以定义变量/信息,类似子向父传递信息

<template v-slot:left="scope">
	<p>我是一个插槽: msg={{ scope.msg }}</p>
</template>
<!--组件定义
<slot name="left"  自定义变量名="val值"></slot>
-->
<slot name="left"  msg="作用域插槽"></slot>

5. 自定义指令

  • 私有自定义指令
directives: {
    color: {
      // bing() 中的el参数表示添加指令的dom元素对象
      // binding表示指令参数值
      bind(el, binding) {
        el.style.color = binding.value
      }
    }
  }

但是bind只在绑定的时候出现一次,当指令的数据具有响应式,需要使用update属性

directives: {
    color: {
      bind(el, binding) {
        el.style.color = binding.value
      },
      update(el, binding) {
        el.style.color = binding.value
      }
    }
  }

如果bindupdate逻辑相似,可以使用简写形式:

directives: {
    color(el, binding) {
      el.style.color = binding.value
    }
  }
  • 全局自定义指令

main.js入口文件中绑定:

Vue.directive('color', function(el, binding) {
  el.style.color = binding.value
})

五、混入mixin

<div id="app">
  <hello></hello>
    <other></other>
</div>

<!-- 定义模板template begin -->
<template id="hello">
    <div>
        <a href="#" @click.prevent="onClick">hello</a>
    </div>
</template>

<template id="other">
    <div>
        <a href="#" @click.prevent="onClick">other</a>
    </div>
</template>
<!-- 定义模板template end -->

$vnode是虚拟DOM树中的节点,全局唯一

<script>
    let myMixin = {
        methods: {
            onClick() {
                if (this.$vnode.tag.match('hello')) {
                    console.log('hello');
                    this.helloInternal();
                } else {
                    console.log('other');
                    this.otherInternal();
                }
            }
        }
    }

    const hello = {
        template: '#hello',
        methods: {
            helloInternal() {
                console.log('我是hello内部方法')
            }
        },
        mixins: [myMixin]
    }
    const other = {
        template: '#other',
        methods: {
            otherInternal() {
                console.log('我是other内部方法')
            }
        },
        mixins: [myMixin]
    }
    new Vue({
        el: '#app',
        components: {
            hello: hello,
            other: other
        }
    })
</script>

在这里插入图片描述

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。并以组件中的数据优先显示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值