Vue基础笔记

Vue基础笔记

大鱼 302 2023-05-20

1. 安装

  1. npm init vue@latest
  2. npm install
  3. npm run dev
  4. npm run build
  5. cdn
  6. 启用es模板import { createApp } from ‘https://unpkg.com/vue@3/dist/vue.esm-browser.js
  7. 启用import maps
<script type="importmap">
  {
    "imports": {
      "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
    }
  }
</script>

<div id="app">{{ message }}</div>

<script type="module">
  import { createApp } from 'vue'

  createApp({
    data() {
      return {
        message: 'Hello Vue!'
      }
    }
  }).mount('#app')
</script>
  1. 选项式 API (Options API) 与 组合式 API (Composition API) 地址

2. 创建应用

  1. 创建应用实例
import { createApp } from 'vue'

const app = createApp({
  /* 根组件选项 */
})
  1. 挂载应用 app.mount(‘#app’)
  2. 应用实例会暴露一个 .config 对象允许我们配置一些应用级的选项
#定义一个应用级的错误处理器,用来捕获所有子组件上的错误:
app.config.errorHandler = (err) => {
  /* 处理错误 */
}
  1. 注册一个组件
app.component('TodoDeleteButton', TodoDeleteButton)
  1. 性能问题
如果你正在使用 Vue 来增强服务端渲染 HTML,并且只想要 Vue 去控制一个大型页面中特殊的一小部分,应避免将一个单独的 Vue 应用实例挂载到整个页面上,而是应该创建多个小的应用实例,将它们分别挂载到所需的元素上去。

3. 模板语法

  1. 双大括号绑定值
  2. v-html绑定原生html 插入
  3. 绑定一个 attribute,应该使用 v-bind, 可以绑定一个值, 也可以绑定一个对象
<div v-bind:id="dynamicId"></div>
#简洁写法
<div :id="dynamicId"></div>
#bool类型
<button :disabled="isButtonDisabled">Button</button>
  1. 绑定值使用 JavaScript 表达式, 或者调用一个方法
{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div :id="`list-${id}`"></div>
#调用方法
 {{ formatDate(date) }}
  1. 指令 Directives
#v-for、v-on 和 v-slot
<p v-if="seen">Now you see me</p>
  1. 参数 Arguments
<a v-bind:href="url"> ... </a>
<!-- 简写 -->
<a :href="url"> ... </a>

<a v-on:click="doSomething"> ... </a>
<!-- 简写 -->
<a @click="doSomething"> ... </a>
  1. 动态参数
<!--
注意,参数表达式有一些约束,
参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释
-->
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>

<!-- 你还可以将一个函数绑定到动态的事件名称上:-->
<a v-on:[eventName]="doSomething"> ... </a>
<!-- 简写 -->
<a @[eventName]="doSomething">
  1. 动态参数语法的限制
<!-- 这会触发一个编译器警告  比如空格和引号-->
<a :['foo' + bar]="value"> ... </a>

<!-- 避免在名称中使用大写字母,因为浏览器会强制将其转换为小写-->
<a :[someAttr]="value"> 这段代码将不会工作 </a> 
  1. 修饰符 Modifiers
<!-- .prevent 修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault():-->
<form @submit.prevent="onSubmit">...</form>

4. 响应式基础

  1. 响应式配置
<script setup>
import { reactive } from 'vue'

const state = reactive({ count: 0 })

function increment() {
  state.count++
}
</script>

<template>
  <button @click="increment">
    {{ state.count }}
  </button>
</template>
  1. 若要等待一个状态改变后的 DOM 更新完成,你可以使用 nextTick() 这个全局 API:
import { nextTick } from 'vue'

function increment() {
  state.count++
  nextTick(() => {
    // 访问更新后的 DOM
  })
}

  1. reactive() 的局限性
  • 仅对对象类型有效(对象、数组和 Map、Set 这样的集合类型),而对 string、number 和 boolean 这样的 原始类型 无效。
  • Vue 的响应式系统是通过属性访问进行追踪的, 我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失:
  1. 用 ref() 响应式变量 代替reactive

  2. 计算属性

// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})

计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果

5. 绑定 HTML class

  1. 绑定对象
<div
  class="static"
  :class="{ active: isActive, 'text-danger': hasError }"
></div>
  1. 绑定数组
const activeClass = ref('active')
const errorClass = ref('text-danger')

<div :class="[activeClass, errorClass]"></div>
  1. 内嵌样式
const activeColor = ref('red')
const fontSize = ref(30)
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

6. 条件渲染

  1. v-if 、v-else、 v-else-if
  2. “template”标签 上的 v-if
  3. v-show 不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。
  4. v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

7. 列表渲染

  1. v-for
<li v-for="item in items">
  {{ item.message }}
</li>
#index
<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
  1. v-for 与对象
const myObject = reactive({
 title: 'How to do lists in Vue',
 author: 'Jane Doe',
 publishedAt: '2016-04-10'
})


<li v-for="value in myObject">
   {{ value }}
 </li>

<li v-for="(value, key) in myObject">
 {{ key }}: {{ value }}
</li>

<li v-for="(value, key, index) in myObject">
 {{ index }}. {{ key }}: {{ value }}
</li>
  1. template 上的 v-for
<ul>
 <template v-for="item in items">
   <li>{{ item.msg }}</li>
   <li class="divider" role="presentation"></li>
 </template>
</ul>
  1. v-for 与 v-if
    当它们同时存在于一个节点上时,v-if 比 v-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:
<template v-for="todo in todos">
 <li v-if="!todo.isComplete">
   {{ todo.name }}
 </li>
</template>
  1. 通过 key 管理状态
    推荐在任何可行的时候为 v-for 提供一个 key attribute,除非所迭代的 DOM 内容非常简单 (例如:不包含组件或有状态的 DOM 元素),或者你想有意采用默认行为来提高性能。
<div v-for="item in items" :key="item.id">
 <!-- 内容 -->
</div>

<template v-for="todo in todos" :key="todo.name">
 <li>{{ todo.name }}</li>
</template>
  1. 数组变化侦测
    Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:
  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()
  1. 计算属性中使用 reverse() 和 sort() 的时候务必小心!这两个方法将变更原始数组,计算函数中不应该这么做。请在调用这些方法之前创建一个原数组的副本:

8. 事件处理

  1. 监听事件
    v-on 指令 (简写为 @) 用法:v-on:click=“handler” 或 @click=“handler”
  2. 事件修饰符, Vue 为 v-on 提供了事件修饰符。修饰符是用 . 表示的指令后缀,包含以下这些:
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>

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

<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>

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

<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>

<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>

<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>

<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>
  1. 按键修饰符
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />

<input @keyup.page-down="onPageDown" />
  1. 按键别名
    Vue 为一些常用的按键提供了别名:
  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

9. 表单输入绑定

  1. 基本用法
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />

<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>

<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>


# checkedNames 数组将始终包含所有当前被选中的框的值。
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>

# 选择器
<div>Selected: {{ selected }}</div>
<select v-model="selected">
  <option disabled value="">Please select one</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
  1. v-for 动态渲染
const selected = ref('A')
const options = ref([
  { text: 'One', value: 'A' },
  { text: 'Two', value: 'B' },
  { text: 'Three', value: 'C' }
])

<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.text }}
  </option>
</select>
<div>Selected: {{ selected }}</div>
  1. 修饰符
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />

# 你想让用户输入自动转换为数字
<input v-model.number="age" />

# 想要默认自动去除用户输入内容中两端的空格
<input v-model.trim="msg" />

10. 生命周期钩子

  1. onMounted 钩子可以用来在组件完成初始渲染并创建 DOM 节点后运行代码
    image

11. 侦听器

  1. watch 函数直接侦听一个 ref
// 可以直接侦听一个 ref
watch(question, async (newQuestion, oldQuestion) => {
 if (newQuestion.indexOf('?') > -1) {
   answer.value = 'Thinking...'
   try {
     const res = await fetch('https://yesno.wtf/api')
     answer.value = (await res.json()).answer
   } catch (error) {
     answer.value = 'Error! Could not reach the API. ' + error
   }
 }
})
  1. 侦听数据源类型
    watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:

  2. 深层侦听器,
    直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发:

const obj = reactive({ count: 0 })

watch(obj, (newValue, oldValue) => {
  // 在嵌套的属性变更时触发
  // 注意:`newValue` 此处和 `oldValue` 是相等的
  // 因为它们是同一个对象!
})

obj.count++
  1. 即时回调的侦听器immediate: true
    watch 默认是懒执行的:仅当数据源变化时,才会执行回调, 有时候需要在创建侦听器时,立即执行一遍回调
watch(source, (newValue, oldValue) => {
  // 立即执行,且当 `source` 改变时再次执行
}, { immediate: true })
  1. watchEffect()
    watchEffect() 允许我们自动跟踪回调的响应式依赖, 不用使用immediate: true,
watchEffect(async () => {
 const response = await fetch(
   `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
 )
 data.value = await response.json()
})
  1. 回调的触发时机watchPostEffect()

默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用。这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。
如果想在侦听器回调中能访问被 Vue 更新之后的 DOM,你需要指明 flush: ‘post’ 选项:

watch(source, callback, {
  flush: 'post'
})

watchEffect(callback, {
  flush: 'post'
})

import { watchPostEffect } from 'vue'
watchPostEffect(() => {
  /* 在 Vue 更新后执行 */
})
  1. 停止侦查器
    侦听器必须用同步语句创建:如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏。
    要手动停止一个侦听器,请调用 watch 或 watchEffect 返回的函数:
const unwatch = watchEffect(() => {})

// ...当该侦听器不再需要时
unwatch()

12. 模板引用

允许我们在一个特定的 DOM 元素或子组件实例被挂载后,获得对它的直接引用, 然后对元素进行必要业务操作, 比如在组件挂载时将焦点设置到一个 input 元素上

  1. 访问独立元素模板引用
<script setup>
import { ref, onMounted } from 'vue'

// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null)

onMounted(() => {
  input.value.focus()
})
</script>

<template>
  <input ref="input" />
</template>
  1. v-for 中的模板引用
<script setup>
import { ref, onMounted } from 'vue'

const list = ref([
  /* ... */
])

const itemRefs = ref([])
onMounted(() => console.log(itemRefs.value))
</script>
<template>
  <ul>
    <li v-for="item in list" ref="itemRefs">
      {{ item }}
    </li>
  </ul>
</template>
  1. 函数模板引用
    除了使用字符串值作名字,ref attribute 还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数:
<input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }">
  1. 组件上的 ref
    模板引用也可以被用在一个子组件上。这种情况下引用中获得的值是组件实例:
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'

const child = ref(null)

onMounted(() => {
  // child.value 是 <Child /> 组件的实例
})
</script>

<template>
  <Child ref="child" />
</template>

13. 组件基础

  1. 传递 数据props, defineProps([‘title’])
<script setup>
defineProps(['title'])
</script>

<template>
  <h4>{{ title }}</h4>
</template>
<!-- BlogPost.vue -->
<script setup>
defineProps(['title'])
</script>

<template>
  <h4>{{ title }}</h4>
</template>




<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />
  1. 传递监听事件defineEmits([‘enlarge-text’])
<script setup>
const emit = defineEmits(['enlarge-text'])

emit('enlarge-text')
</script>
  1. 通过slot 插槽数据
<template>
  <div class="alert-box">
    <strong>This is an Error for Demo Purposes</strong>
    <slot />
  </div>
</template>

<style scoped>
.alert-box {
  /* ... */
}
</style>


<AlertBox>
  Something bad happened.
</AlertBox>
  1. 动态组件
<component :is="tabs[currentTab]" class="tab"></component>

当使用component :is=“…” 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过 KeepAlive 组件强制被切换掉的组件仍然保持“存活”的状态。