Vue 基本使用知识点整理

时间:2021-6-19 作者:qvyue

Vue 基本使用

指令,插值

  • 插值,表达式
  • 指令,动态属性
  • v-html:会有 XSS 风险,会覆盖子组件

文本插值 {{message}}

JS 表达式 {{ flag ? 'yes' : 'no' }} (只能是表达式,不能是 js 语句)

动态属性 id


有 xss 风险 【注意】使用 v-html 之后,将会覆盖子元素

export default { data() { return { message: 'hello vue', flag: true, rawHtml: '指令 - 原始 html 加粗 斜体', dynamicId: `id-${Date.now()}` } } }

computed 和 watch

  • computed 有缓存,data 不变则不会重新计算
  • computed 可以设置 set 和 get 方法
  • watch 深度监听
    • watch 默认不是深度监听
    • 启动深度监听的话需要设置 deep 为 true
  • watch 监听引用类型,拿不到 old value

computed demo

num {{num}}

double1 {{double1}}

export default { data() { return { num: 20 } }, computed: { double1() { return this.num * 2 }, double2: { get() { return this.num * 2 }, set(val) { this.num = val/2 } } } }

watch demo

export default { data() { return { name: '吉良吉影', info: { city: '上海' } } }, watch: { name(oldVal, val) { console.log('watch name', oldVal, val) // 值类型,可正常拿到 oldVal 和 val }, info: { handler(oldVal, val) { console.log('watch info', oldVal, val) // 引用类型,拿不到 oldVal 。因为指针相同,此时已经指向了新的 val }, deep: true // 深度监听 } } }

class 和 style

注意事项

  • 使用动态属性
  • 使用驼峰式写法

代码演示

使用 class

使用 class (数组)

使用 style

export default { data() { return { isBlack: true, isYellow: true, black: 'black', yellow: 'yellow', styleData: { fontSize: '40px', // 转换为驼峰式 color: 'red', backgroundColor: '#ccc' // 转换为驼峰式 } } } } .black { background-color: #999; } .yellow { color: yellow; }

条件渲染

  • v-if , v-else 的用法,可使用变量,也可使用 === 表达式
  • v-if 和 v-show 的区别?
    • v-if 会直接销毁和加载 DOM
    • v-show 修改 display 属性为显示或隐藏
  • v-if 和 v-show 的使用场景?
    • 频繁切换显示隐藏场景使用 v-show
    • 非频繁切换显示隐藏场景(如切换注册/登录)可使用 v-if

代码演示

A

B

other

A by v-show

B by v-show

export default { data() { return { type: 'a' } } }

循环(列表)渲染

注意事项

  • v-for 可遍历对象
  • key 不可乱写(如 random 或者 index)
  • v-for 和 v-if 不建议一起使用!

代码演示

遍历数组

  • {{index}} - {{item.id}} - {{item.title}}

遍历对象

  • {{index}} - {{key}} - {{val.title}}
export default { data() { return { flag: false, listArr: [ { id: 'a', title: '标题1' }, // 数据结构中,最好有 id ,方便使用 key { id: 'b', title: '标题2' }, { id: 'c', title: '标题3' } ], listObj: { a: { title: '标题1' }, b: { title: '标题2' }, c: { title: '标题3' }, } } } }

事件

  • event参数,自定义参数
    • 在不传自定义参数的情况下,event 对象可以直接在函数形参获取
    • 传入自定义参数情况下,需要将 $event 传入
    • 此 event 是原生的 event 对象
  • 事件修饰符,按键修饰符
    • stop 阻值点击事件继续传播
    • prevent 提交事件不再重载页面
    • v-on:click.stop.prevent 修饰符可以串联使用
  • 【观察】事件被绑定到哪里?
    • Vue 的事件是被挂载到当前元素的

代码演示

{{num}}

export default { data() { return { num: 0 } }, methods: { increment1(event) { console.log('event', event, event.__proto__.constructor) // 是原生的 event 对象 console.log(event.target) console.log(event.currentTarget) // 注意,事件是被注册到当前元素的,和 React 不一样 this.num++ // 1. event 是原生的 // 2. 事件被挂载到当前元素 // 和 DOM 事件一样 }, increment2(val, event) { console.log(event.target) this.num = this.num + val }, loadHandler() { // do some thing } }, mounted() { window.addEventListener('load', this.loadHandler) }, beforeDestroy() { //【注意】用 vue 绑定的事件,组建销毁时会自动被解绑 // 自己绑定的事件,需要自己销毁!!! window.removeEventListener('load', this.loadHandler) } }

表单

  • v-model 双向数据绑定
  • 常见表单项 textarea checkbox radio select
  • 修饰符 lazy(类似防抖效果) number(只能输入数字) trim(去除两边空格)

代码演示

输入框: {{name}}

多行文本: {{desc}}

复选框 {{checked}}

多个复选框 {{checkedNames}}

单选 {{gender}}

下拉列表选择 {{selected}}

请选择 A B C

下拉列表选择(多选) {{selectedList}}

请选择 A B C
export default { data() { return { name: '吉良吉影', age: 33, desc: '自我介绍', checked: true, checkedNames: [], gender: 'male', selected: '', selectedList: [] } } }

其他

  • v-once 让某元素标签只渲染一次
  • ref 写在标签上可以通过 this.$refs 获取操作 DOM 节点

    • ref 还可以写在子组件上,从而获取子组件的引用

组件

props 和 $emit

  • props 父组件向子组件传递信息
  • $emit 子组件向父组件触发一个事件
  • 实现父子组件之间通讯

父组件

import Input from './Input' import List from './List' export default { components: { Input, List }, data() { return { list: [ { id: 'id-1', title: '标题1' }, { id: 'id-2', title: '标题2' } ] } }, methods: { addHandler(title) { this.list.push({ id: `id-${Date.now()}`, title }) }, deleteHandler(id) { this.list = this.list.filter(item => item.id !== id) } }, created() { console.log('index created') }, mounted() { console.log('index mounted') }, beforeUpdate() { console.log('index before update') }, updated() { console.log('index updated') }, }

Input 组件

import event from './event' export default { data() { return { title: '' } }, methods: { addTitle() { // 调用父组件的事件 this.$emit('add', this.title) // 调用自定义事件 event.$emit('onAddTitle', this.title) this.title = '' } } }

List 组件

  • {{item.title}}
import event from './event' export default { // props: ['list'] props: { // prop 类型和默认值 list: { type: Array, default() { return [] } } }, data() { return { } }, methods: { deleteItem(id) { this.$emit('delete', id) }, addTitleHandler(title) { console.log('on add title', title) } }, created() { console.log('list created') }, mounted() { console.log('list mounted') // 绑定自定义事件 event.$on('onAddTitle', this.addTitleHandler) }, beforeUpdate() { console.log('list before update') }, updated() { console.log('list updated') }, beforeDestroy() { // 及时销毁,否则可能造成内存泄露 event.$off('onAddTitle', this.addTitleHandler) } }

自定义事件

  • 创建一个 event.js (如下图)
  • 通过在 event 上绑定自定义事件,调用自定义事件实现兄弟组件之间通讯(上图代码所示)
// event.js
import Vue from 'vue'

export default new Vue()

生命周期

单个组件

生命周期图示

带有父子组件的生命周期

  • 初始化父子组件执行顺序

先触发父元素,然后子元素先进行,父元素收尾。

父beforeCreate => 父created => 父beforeMount => 子beforeCreate => 子created => 子beforeMount

=> 子mounted => 父mounted

先父组件创建虚拟dom,再子组件创建虚拟dom 。初始化先保证父组件初始化完再初始化子组件。(外 => 内)

然后子组件渲染,再父组件渲染 。渲染先保证子组件渲染完再渲染父组件 (内 => 外)

最先开始创建的是最外层组件,但是最先创建完的是最内层组件。 => 类似先进后出(栈)。

  • 删除子组件触发生命周期顺序

先触发父元素,然后子元素先进行,父元素收尾。

父beforeUpdate => 子beforeDestroy => 子destroyed => 父updated

  • 更新子组件触发生命周期顺序

先触发父元素,然后子元素先进行,父元素收尾。

父beforeUpdate => 子beforeUpdate => 子updated => 父updated

首先是修改父组件的data,所以触发父组件的beforeUpdate,它要把更新后数据再传递给给子组件,子组件更新props,因此再触发子组件的beforeUpdate,紧接着渲染页面触发子组件的updated,只有子组件渲染完页面后,这个时候父组件也就渲染完,触发父组件的updated。

Non-Props

  • 父组件向子组件传值,子组件没有通过 props 接收,那么子组件会把该属性变成子组件最外层的 DOM 上的一个属性
  • 如果不希望发生此特性那么可以在子组件上加 一条属性:inheritAttrs: false
  • 子组件可以通过 this.$attrs 手动获取 non-props 属性

插槽

  • slot 中使用的作用域的问题

    • 父模板里调用的数据属性,使用的都是父模板里的数据
    • 子模板里调用的数据属性,使用的都是子模板里的数据
  • 具名插槽

    • 父组件传递时加上属性 v-slot="..." 可简写为 #...
    • 子组件
  • 作用域插槽

    • 代码演示:

    • const app = Vue.createApp({
          template: `
                 // 可简写为 ES6 解构形式 v-slot="{ item }", 则下面直接用 item 即可
                  {{ slotProps.item }}   // 2. slotProps.item 就是子组件传入的数据
              
          `
      })
      
      app.component('List', {
          data() { return { list: [1, 2, 3] } },
          template: `
              
      // 1. 将item传给父组件
      ` })
    • 分析上面代码:

    • 父组件调子组件的时候传入 slot 进来

    • 子组件通过 :item=item 把数据传给父组件

    • 作用域插槽解决了什么问题?

      • 当子组件渲染的内容要由父组件决定的情况
      • 通过作用域插槽,可以让使父组件调用子组件里的数据
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。