VUE3 学习日记(二)

一、类与样式绑定

1.1 绑定 HTML class

直接上例子 :

const isActive = ref(true)
const hasError = ref(false)

<div
  class="static"
  :class="{ active: isActive, 'text-danger': hasError }"
></div>

//最终
<div class="static active"></div>

当 isActive 或者 hasError 改变时,class 列表会随之更新。

也可以绑定一个对象或者绑定一个返回一个对象的计算属性:

const classObject = reactive({
  active: true,
  'text-danger': false
})

<div :class="classObject"></div>

=====================================
const isActive = ref(true)
const error = ref(null)

const classObject = computed(() => ({
  active: isActive.value && !error.value,
  'text-danger': error.value && error.value.type === 'fatal'
}))


<div :class="classObject"></div>

还可以绑定数组    还可以用三元表达式:

const activeClass = ref('active')
const errorClass = ref('text-danger')

<div :class="[activeClass, errorClass]"></div>
***************************************
三元表达式

<div :class="[isActive ? activeClass : '', errorClass]"></div>

errorClass 会一直存在,但 activeClass 只会在 isActive 为真时才存在。

还可以更复杂  如数组中嵌套对象
<div :class="[{ active: isActive }, errorClass]"></div>

1.2 在组件上使用

就是在组件上直接给一个class  属性  
<MyComponent class=”baz boo” />

1.3 绑定内联样式

使用  :style   来实现内联样式添加  

const activeColor = ref('red')
const fontSize = ref(30)

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

const styleObject = reactive({
  color: 'red',
  fontSize: '13px'
})

<div :style="styleObject"></div>

绑定数组也可以 
<div :style=”[baseStyles, overridingStyles]”></div>

二、条件渲染

2.1 v-if    v-else  v-else-if

  v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。

你也可以使用 v-else 为 v-if 添加一个“else 区块”。

注:一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。

<button @click="awesome = !awesome">Toggle</button>

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

 v-else-if    和 v-else 类似,一个使用 v-else-if 的元素必须紧跟在一个 v-if 或一个 v-else-if 元素后面。

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

2.2  v-if 与 v-show

这两者的用法是一样的   但是实际渲染不一样   

首先v-if 是真实的按条件渲染  因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建 

v-show 简单许多 元素无论初始值条件如何  始终会被渲染  也就是css 中display的属性会被切换

总得来说  v-if的有高的切换开销  如果需要频繁的切换  v-show会好一点 

注意:原则上v-if和v-for是不推荐同时使用的   如果同时存在的话  v-if会优先被执行

三、列表渲染

3.1 v-for

我们可以使用 v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名

const items = ref([{ message: 'Foo' }, { message: 'Bar' }])

<li v-for="(item,index)in items" :key='item.id'>
  {{ item.message }}
</li>

在 v-for 块中可以完整地访问父作用域内的属性和变量。v-for 也支持使用可选的第二个参数表示当前项的位置索引。注意  我们还要加上一个key值  最好是id 等唯一值  最好不要index(可以用)

还可以渲染对象  遍历的顺序会基于该对象调用Object.keys() 的返回值来决定。

const myObject = reactive({
  title: 'How to do lists in Vue',
  author: 'Jane Doe',
  publishedAt: '2016-04-10'
})

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

3.2 <template> 上的 v-for

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

当遇到v-for 与 v-if 同时使用的话  我们可以这样做

<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

3.3 组件上使用 v-for

在组件中使用 v-for  别忘了提供一个key   如果数据传递给组件的话 需要传递props  如:

<MyComponent
  v-for="(item, index) in items"
  :item="item"
  :index="index"
  :key="item.id"
/>

3.4 数组变化侦测

变更数组方法的有 :push()  pop()  shift()  unshift()  splice()  sort()  reverse() 

还有一些方法是不会对原数组进行变更的 :filter()concat() 和 slice()  他们会返回一个新的数组

四、事件处理

4.1 使用方法

在vue中  我们用v-on指令来绑定监听dom事件  用法:                                                                                     v-on:click="methodName" 或 @click="handler"

在内联处理器中调用方法  允许我们向方法传入自定义参数以代替原生事件(e)

在内联事件处理器中访问事件参数 (两种方式 ):

<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>

<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
  Submit
</button>


function warn(message, event) {
  // 这里可以访问原生事件
  if (event) {
    event.preventDefault()
  }
  alert(message)
}

4.2 事件修饰符

vue提供了一些事件修饰符  .stop  .prevent  .self  .capture  .once  .passive

<!-- 单击事件将停止传递 -->
<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>

4.3 按键修饰符

vue提供了一些按键修饰符: .enter  .tab  .delete  .esc  .space  .up  .down  .left  .right 

<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />

<input @keyup.page-down="onPageDown" />

五、表单输入

5.1  利用 v-model 来监听值的变化  

文本类型的 <input> 和 <textarea> 元素会绑定 value property 并侦听 input 事件;

<input type="checkbox"> 和 <input type="radio"> 会绑定 checked property 并侦听 change 事件;

<select> 会绑定 value property 并侦听 change 事件。

复选框和单选框的使用方法   需要id和for来绑定 如:

<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
*********************************************************
<div>Picked: {{ picked }}</div>

<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>

<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>

5.2 修饰符

vue提供了一些修饰符给我们  :

..lazy:v-model 会在每次 input 事件后更新数据  可以添加 lazy 修饰符来改为在每次 change 事件后更新数据

.number:如果你想让用户输入自动转换为数字,可以在 v-model 后 .number 修饰符来管理输入:

.trim : 想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符

六、生命周期

6.1   基础  

每个vue组件实例在创建时都需要经历一系列的初始化步骤  类似于出生到死亡。

主要有以下生命钩子 :beforeCreate   created  beforeMount(还没创建dom节点)  mounted(常用)  beforeUpdate  updated(常用)

 beforeUnmount    unmounted(常用)   errorCaptured

vue 官方图示 

七、侦听器 Watch

7.1  基础用法   

可以用侦听器来侦听一个ref的变化  并触发相应的回调函数的逻辑  例子:

<script setup>
import { ref, watch } from 'vue'

const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')

// 可以直接侦听一个 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
    }
  }
})
</script>

<template>
  <p>
    Ask a yes/no question:
    <input v-model="question" />
  </p>
  <p>{{ answer }}</p>
</template>

7.2 侦听数据源类型

watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组,注意,你不能直接侦听响应式对象的属性值,例如:

const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
  console.log(`x is ${newX}`)
})

// getter 函数
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})


//不能直接侦听响应式对象的属性值
const obj = reactive({ count: 0 })

// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})
//正确做法是
// 提供一个 getter 函数
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)

7.3 深层侦听器

直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发。可以加上一个deep 选项  强制转成深层侦听器:

watch(
  () => state.someObject,
  (newValue, oldValue) => {
    // 注意:`newValue` 此处和 `oldValue` 是相等的
    // *除非* state.someObject 被整个替换了
  },
  { deep: true }
)

7.4 即时回调的侦听器

watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但是在某些业务场景下  需要我们在创建侦听器的时候 立即执行一遍回调。比如我们想请求一些初始数据 然后在相关状态更改时重新请求数据。我们可以传入 immediate: true 选项来强制侦听器的回调立即执行

watch(source, (newValue, oldValue) => {
  // 立即执行,且当 `source` 改变时再次执行
}, { immediate: true })

7.5  watchEffect()

watcheffect() 函数可以让我们自动跟踪回调的响应式依赖  所以不需要指定 immediate:true。

如果你需要侦听一个嵌套数据结构中的几个属性,watchEffect() 可能会比深度侦听器更有效,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性。对于有多个依赖项的侦听器来说  使用这个 可以消除手动维护依赖列表的负担。

watch  vs.  watchEffect

watch 只追踪明确侦听的数据源  它不会追踪任何在回调中访问到的东西  而且只有数据源改变时才会触发

watcheffect  它会在同步执行过程中  自动追踪所有能访问到的响应式属性  可以立即执行一遍