vue3知识点

Vue.js

核心是一个允许采用简洁的模板语法来声明式地将数据渲染进DOM的系统
组件本质上是一个具有预定义选项的实例
const app = vue.createApp({ ... }) // 在应用中创建“全局”组件

// 创建 Vue 应用实例
const app = Vue.createApp(...)

// 定义名为 todo-item 的新组件
app.component('todo-item', {
  template: `<li>This is a todo</li>`
})

// 挂载 Vue 应用
app.mount(...)

Demo

const ComponentsApp = {
  data() {
    return {
      groceryList: [
        { id: 0, text: 'Vegetables' },
        { id: 1, text: 'Cheese' },
        { id: 2, text: 'Whatever else humans are supposed to eat' }
      ]
    }
  }
}
// 允许链式写法
// Vue.createApp({})
//  .component('SearchInput', SearchInputComponent)
//  .directive('focus', FocusDirective)
//  .use(LocalePlugin)

const app = Vue.createApp(ComponentsApp)
app.component('todo-item', {
  props: ['todo'],
  template: `<li>{{ todo.text }}</li>`
})
app.mount('#components-app')
<div id="todo-list-app">
  <ol>
     <!--
      现在我们为每个 todo-item 提供 todo 对象
      todo 对象是变量,即其内容可以是动态的。
      我们也需要为每个组件提供一个“key”,稍后再
      作详细解释。
    -->
    <todo-item
      v-for="item in groceryList"
      v-bind:todo="item"
      v-bind:key="item.id"
    ></todo-item>
  </ol>
</div>
一、根组件
  1. 传递给createApp的选项用于配置根组件。当我们挂载应用时,该组件被用作渲染的起点
  2. *** 根组件与其他组件没有什么不同,配置选项是一样的,所对应的组件实例 行为也是一样的
  3. *** mount 返回的是根组件实例,不是应用本身

Vue 应用挂载到 <div id="app"></div>

const RootComponent = { 
  /* 选项 */ 
}
const app = Vue.createApp(RootComponent)
const vm = app.mount('#app') 
二、生命周期
  1. 生命周期函数、选项property(元素属性)或回调上不可使用箭头函数。生命周期钩子this上下文指向调用它的当前活动实例。
  2. 箭头函数并没有this,this作为变量一直向上级词法作用域查找。直至找到为止,经常导致Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
  vue.createApp({
    data() {
      return { count: 1 }
    },
    created() {
      console.log('count is' + this.count) // => count is 1
    }
  })
image.png
三、模板语法

在底层的实现上,Vue将模板编译成虚拟DOM渲染函数。结合响应性系统,Vue能够智能地计算出最少需要重新渲染多少组件,并把DOM操作次数减到最少。
*** v-html不能复合局部模板,因为Vue不是基于字符串的模板引擎,反之,对于用户界面(UI),组件更适合作为可重用和可组合的基本单位
*** 动态渲染任意的HTML是非常危险的,因为很容易导致XSS攻击

1. 文本插值使用双大括号{{ 变量 }}
2. 动态渲染HTML使用v-html
  const RenderHtmlApp = {
    data() {
      return {
        rawHtml: '<span style="color: red">这几个文字是红色</span>'
      }
    }
  }
  Vue.createApp(RenderHtmlApp).mount('#example')
<div id="example">
  <p> v-html解析<span v-html="rawHtml"></span> </p>
</div>
3. 插值双大括号{{ 单个表达式 }}可以使用js表达式
{{ n + 1 }}
{{ ok ? 'Yes' : 'No' }}
{{ arrayData.split(',') }}
...
{{ var a = 1 }} // 不会生效, 这是语句,不是表达式
{{ if( ok ) { return message } }} // 流控制也不会生效
4. v- 指令职责是:当表达式的值改变时,将其产生的连带影响,响应式作用于DOM
5. 参数
<a v-on:click="doSomthing"> ... </a>
6. 动态参数

*** 动态参数预期是求出一个字符串,异常情况下为null。这个null会被显性地用于移除绑定

// 若attrname的值为click
<a v-on:[attrname]="doSomthing">...</a> 
等价于
<a v-on:click="doSomthing">...</a>

*** 在 DOM 中使用模板时 (直接在一个 HTML 文件里撰写模板),还需要避免使用大写字符来命名键名,因为浏览器会把 attribute 名全部强制转为小写:

<!--
在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]`。
除非在实例中有一个名为“someattr”的 property,否则代码不会工作。
-->
<a v-bind:[someAttr]="value"> ... </a>
7. 缩写

v-on

// 完整语法
<a v-on:click="doSomthing">...</a>
// 缩写
<a @click="doSomthing">...</a>
// 动态参数缩写
<a @[attrname]="doSomthing">...</a>

v-bind

// 完整语法
<a v-bind:href="url">...</a>
// 缩写
<a :href="url">...</a>
// 动态参数缩写
<a :[key]="url">...</a>
四、Data Property

vue自动为methods绑定this,以便它始终指向组件实例。这将确保方法再用作事件监听或回调时保持正确的this。定义methods时应避免使用箭头函数

1. vue没有内置的防抖、节流,可以引用lodash

为了使组件实例彼此独立,可以在生命周期钩子created里添加防抖函数

app.component( 'save-button', {
    created() {
      // 使用lodash 防抖函数
      this.debouncedClick = _.debounce(this.click, 500)
    },
    unmounted() {
      // 移除组件时,取消定时器
      this.debouncedClick.cancle()
    },
    methods: {
      click() {
        // ... 响应事件...
      }
    },
    template: `
      <button @click='debouncedClick'> Save </button>
    `
  })
五、计算属性、侦听器
1.computed 计算属性

computed:{ ... }计算属性是基于它们的响应依赖关系缓存的。

以下:如果data的值不发生改变,即使多次访问computFun计算属性会立即返回之前的计算结果,而不必再次执行函数。如果不希望缓存,可用methods来代替

computed: {
  computFun() {
    return this.data == 1 ? '是' :'否'
  }
}

以下计算属性将不再更新,因为Date.now()不是响应式依赖

  computed: {
    now() {
      return Date.now()
    }
  }
2.watch 侦听器

当需要在数据变化时执行异步 或 开销较大的操作时,watch方式最有用

六、条件渲染

v-ifv-else-ifv-elsev-show

1.v-if、v-else-if、v-else

v-if和v-for不推荐同时使用,如果一起使用了v-if的优先级更高

<template>元素当做不可见的包裹元素,在上面使用v-if。最终的渲染结果不包括<template>元素

<template v-if="ok">
 <p>渲染后template标签不存在</p>
</template>
 // ok为true, 渲染结果为
<p>渲染后template标签不存在</p>
2.v-show

v-show的元素始终会被渲染并保留在DOM中,v-show只是简单地切换元素的CSS property display
**** v-show不支持<template>元素,也不支持v-else

3.v-if VS v-show
  • v-if是真正的条件渲染,因为它会确保再切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建
  • v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
  • v-show不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换(样式display控制的显示与隐藏)
  • **** 一般而言,v-if具有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好
七、列表渲染

用v-for把一个数组对应为一组元素

1.数组
  • item为迭代数组元素别名。index为索引。key作为Vue识别节点的一个通用机制,key需使用字符串或数值类型的值
  • v-for可以在template元素中使用

当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染

v-for与v-if同时使用时建议使用以下写法:

<template v-for="(item, index) in items" :key="item.id">
  <li v-if="!item.isShow">{{item.name}}</li>
  <li>{{item.name}}</li>
</template>
2.对象
  • value为value。name为key。index为索引
  • 会按照object.keys()结果遍历对象,但是不能保证它在不同JavaScript引擎下的结果一致
<li v-for="(value, name, index) in myObject">
  {{ index }}. {{ name }}: {{ value }}
</li>
3.数组更新

变更方法:变更调用了这些方法的原始数组
替换数组:即非变更方法,不会变更原始数组,而总是返回一个新数组

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。当你直接修改了对象属性的值,会发现只有数据改了,页面内容没有更新。Vue将被侦听数组的变更方法进行了包裹,所以它们也将会触发视图更新。

  • 变更方法:
    push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  • 替换数组方法:
    filter()、concat() 、slice()
八、事件处理
1. @click监听点击事件
<button @click="btnFun('click me', $event)">点击事件</button>
...
methods: {
  btnFun(msg, event) {
    // doSomthing
  }
}
2. @click多事件处理器
<button @click="one($event), two($event)">处理多事件按钮</button>
...
methods: {
  one(event) {
    // 第一个事件处理逻辑
  },
  two(event) {
    // 第二个事件处理逻辑
  }
}

3. 事件修饰符

.stop、.prevent、.capture、.self、.once、.passive

使用修饰符时,顺序很重要;相应代码会以同样的顺序产生

<!-- 阻止单击事件继续传播 -->
<a @click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form @submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发   -->
<!-- 而不会等待 `onScroll` 完成                   -->
<!-- 这其中包含 `event.preventDefault()` 的情况   -->
<div @scroll.passive="onScroll">...</div>
4. 其它修饰符
  • 按键修饰符:.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right

直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符

<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input @keyup.enter="submit" />
<input @keyup.page-down="onPageDown" />
  • 系统修饰符:.ctrl、.alt、.shift、.meta(在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞))
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
  • .exact 修饰符:.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
  • 鼠标按钮修饰符:.left、.right、.middle
九、表单输入绑定
  • v-model语法糖:可以在表单<input>、<textarea>、<select>等元素上创建双向数据绑定。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理
  • v-model会忽略所有表单元素的valuecheckedselected attribute的初始值而总是将当前活动实例的数据作为数据来源,应该通过JavaScript在组件的data选项中声明初始值
1. 值绑定
<!-- 当选中时,`picked` 为字符串 "a" -->
<input type="radio" v-model="picked" value="a" />

<!-- `toggle` 为 true 或 false -->
<input type="checkbox" v-model="toggle" />

<!-- 当选中第一个选项时,`selected` 为字符串 "abc" -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>
<!-- 当选中时vm.pick === vm.a-->
<input type="radio" v-model="pick" v-bind:value="a" />
2. 修饰符
  • .lazy:在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步。添加.lazy修饰符,可以转为change事件之后进行同步
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" />
  • .number:自动将用户的输入值转为数值类型
<input v-model.number="age" type="number" />
  • .trim: 自动过滤用户输入的首位空白字符
<input v-model.trim="msg" />
十、组件基础
  • 父组件通过props向子组件传递数据
  • 子组件通过调用内建的$emit()并传入事件名称来触发一个事件
<button @click="$emit('enlargeText', 0.1)">
  Enlarge text
</button>
...
methods: {
  onEnlargeText(enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}
1. 动态组件
  • is:不同组件之间进行动态切换

以下currentTabComponent可以包括:已注册的名字 或 一个组件的选项对象

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component :is="currentTabComponent"></component>
  • 有些HTML元素,诸如<table>内只能出现<tr>元素,可以使用is变通
// blog-post-row为 自定义组件
<table>
  <tr is="vue:blog-post-row"></tr> 
</table>
2. 属性名称 大小写

HTML attribute 名不区分大小写,因此浏览器将所有大写字符解释为小写。这意味着当你在 DOM 模板中使用时,驼峰 prop 名称和 event 处理器参数需要使用它们的 kebab-cased (横线字符分隔) 等效

app.component('blog-post', {
  props: ['postTitle'],
  template: `
    <h3>{{ postTitle }}</h3>
  `
})
...
<blog-post post-title="hello!"></blog-post>
十一、组件注册
1.全局注册: 在注册以后可以用在任何新创建的组件实例模板中

app.component的第一个参数是组件名

const app = Vue.createApp({ ... })
app.component('my-component-name', {
  ...
})

...
<my-component-name></my-component-name>
2.局部注册: 在components选项中定义组件以后才可使用

局部注册的组件在其子组件中不可使用

在 ComponentB 中可用ComponentA。举例:

const ComponentA = {
  /* ... */
}

const ComponentB = {
  components: {
    'component-a': ComponentA
  }
  // ...
}

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentC
  }
  // ...
}
十二、props:父组件向子组件传值

props单向下绑定的数据流向。数据只能从父组件流向子组件,在子组件中不可修改prop

app.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default() {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator(value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 具有默认值的函数
    propG: {
      type: Function,
      // 与对象或数组默认值不同,这不是一个工厂函数 —— 这是一个用作默认值的函数
      default() {
        return 'Default function'
      }
    }
  }
})
  • type 还可以是一个自定义的构造函数

用于验证author prop的值是否通过new Person创建的。举例:

function Person(firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}

...可以使用

app.component('blog-post', {
  props: {
    author: Person
  }
})
  • prop的大小写命名
    HTML中的attribute名是大小写不敏感的,所以浏览器会把所有的大写字符解释为小写字符。这意味着当你使用DOM中的模板时,驼峰命名法的prop名需要使其等价的短横线分割命名
const app = Vue.createApp({})

app.component('blog-post', {
  // camelCase in JavaScript
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})

...

<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容