本文主要基于 ts 和 vue3 的组合式 api

<script setup>
import { ref } from 'vue'
const awesome = ref(true)
function toggle() {
    // ...
    awesome.value = !awesome.value
    //awesome = !awesome  这里不能直接这样
}
</script>
    
<template>
    <button @click="toggle">toggle</button>
    <h1 v-if="awesome">Vue is awesome!</h1>
    <h1 v-else>Oh no 😢</h1>
</template>
<form @submit.prevent="addMemo"></form>

.prevent 表示提交以后不刷新页面(在 vue 中如此使用是因为有响应式了),prevent 是 preventDefault, 阻止标签默认行为,有些标签有默认行为,例如 a 标签的跳转链接属性 href 等。

submit 点击默认行为是提交表单,这里并不需要它提交,只需要执行 addMemo 方法,故阻止为好。

<script setup>
import { ref, computed } from 'vue'
let id = 0
const newTodo = ref('')
const hideCompleted = ref(false)
const todos = ref([
    { id: id++, text: 'Learn HTML', done: true },
    { id: id++, text: 'Learn JavaScript', done: true },
    { id: id++, text: 'Learn Vue', done: false }
])
const filteredTodos = computed(() => {
    return hideCompleted.value
        ? todos.value.filter((t) => !t.done)
        : todos.value  # 返回的是响应式对象的value,而不是响应式对象
})
function addTodo() {
    todos.value.push({ id: id++, text: newTodo.value, done: false })
    newTodo.value = ''
}
function removeTodo(todo) {
    todos.value = todos.value.filter((t) => t !== todo)
}
</script>
    
<template>
    <form @submit.prevent="addTodo">
        <input v-model="newTodo" />
        <button>Add Todo</button>
    </form>
    <ul>
        <li v-for="todo in filteredTodos" :key="todo.id">
            <input type="checkbox" v-model="todo.done">
            <span :class="{ done: todo.done }">{\{ todo.text }}</span>
            <button @click="removeTodo(todo)">X</button>
        </li>
    </ul>
    <button @click="hideCompleted = !hideCompleted">
        {\{ hideCompleted ? 'Show all' : 'Hide completed' }}
    </button>
</template>
    
<style>
.done {
    text-decoration: line-through;
}
</style>

在上面使用计算属性的例子中, v-for 在 template 标签中直接渲染的是计算属性的值而不是原来的数组,而且,在计算属性中,传入的函数返回的是响应式对象的 value,而不是响应式对象。

模板引用

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

const p = ref(null)

onMounted(() => {
  p.value.textContent = 'mounted!'
})
</script>

<template>
  <p ref="p">hello</p>
</template>

同名,初始化时用 null,因为还不存在 dom 元素。访问时用 p.value 再加 .属性名

Emits

App.vue

<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'
const childMsg = ref('No child msg yet')
</script>
<template>
  <ChildComp @response="(msg) => childMsg = msg"/>
  <p>{\{ childMsg }}</p>
</template>

ChildComp.vue

<script setup>
const emit = defineEmits(['response'])

emit('response', 'hello from child')
</script>

<template>
  <h2>Child component</h2>
</template>

===
三个等号我们称为等同符,当等号两边的值为相同类型的时候,直接比较等号两边的值,值相同则返回 true,若等号两边的值类型不同时直接返回 false。

1662634802150

class 和 style 的绑定

1. 绑定 HTML Class 对象绑定

我们用传给 v-bind:class 一个对象,动态切换 class 是否存在

<div v-bind:class="{ active: isActive }"></div> ; //这里我们使用isActive 这个变量动态判断active是否显示到html

vue 对象里面

data: {
	isActive:true,//判断是否显示active这个class
}

页面渲染为:

<div class="active"></div>

当然我们也可以对象中传入更多属性来动态切换多个 class,此外,v-bind:class 指令也可以与普通的 class 属性共存。

<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> 
	动态切换多个 class
</div>

vue 对象里面

data: {
	isActive:true,	
	hasError:false
}

页面渲染为:

`<div class="static active">` 动态切换多个 class`</div>`

对于上面 v-bind:class 指令我们也可以传一个对象

<div v-bind:class="classObject">动态切换多个 class</div>
data: {
	classObject: {	
		active: true,
		'text-danger': false
	}
}

页面渲染为:

<div class="active"> 动态切换多个 class</div>

对于动态 class 绑定我们也可以通过计算属性返回对象来动态判断 class 的绑定值

<div v-bind:class="classObject"></div>
data: {
	isActive: true,
	error: null
},
computed: {
	classObject: function () {
	return {
		active: this.isActive && !this.error,
		'text-danger': this.error && this.error.type === 'fatal'
	}
}

2. 绑定 HTML Class 数组语法

除了对象语法绑定 class, 我们还有一种方法是数组语法,我们可以把一个数组传给 v-bind:class。

<div v-bind:class="[activeClass, errorClass]"></div>
data: {
	activeClass: 'active',
	errorClass: 'text-danger'
}

页面渲染为

<div class="active text-danger"></div>

// 这里判断是如果 isActive 为 true 显示 activeClass ,errorClass,否则只显示 errorClass

对于 class 绑定当有多个条件 class 时这样写有些繁琐,在数组语法中也可以使用对象语法,例如如下写法:

<div v-bind:class="[{ active: isActive }, errorClass]"></div>
<!--
现在我们将元素的 attribute /property 响应式地绑定到状态上。
这个 :title 语法是 v-bind:title 的简写。
-->
<script setup>
import { ref } from 'vue'
const message = ref('Hello World!')
const isRed = ref(true)
const color = ref('green')
function toggleRed() {
  isRed.value = !isRed.value
}
function toggleColor() {
  color.value = color.value === 'green' ? 'blue' : 'green'
}
</script>
<template>
  <p>
    <span :title="message">
      Hover your mouse over me for a few seconds to see my dynamically bound title!
    </span>
  </p>
  <!--
  除了普通字符串之外,
  class 绑定还特别支持了对象和数组
  -->
  <p :class="{ red: isRed }" @click="toggleRed">
    This should be red... but click me to toggle it.
  </p>
  <!-- 样式绑定也支持对象和数组 -->
  <p :style="{ color }" @click="toggleColor">
    This should be green, and should toggle between green and blue on click.
  </p>
</template>
<style>
.red {
  color: red;
}
</style>

对于样式的对象绑定,在上面绑定的是创建的 ref 对象 color,就是键值对的形式,所以直接将 color 加一个大括号后放在 style 的双引号中

<!--
我们可以使用 v-model 指令在状态和表单输入之间创建双向绑定。
-->
<script setup>
import { ref } from 'vue'
const text = ref('Edit me')
const checked = ref(true)
const checkedNames = ref(['Jack'])
const picked = ref('One')
const selected = ref('A')
const multiSelected = ref(['A'])
</script>
<template>
  <h2>Text Input</h2>
  <input v-model="text"> {\{ text }}
  <h2>Checkbox</h2>
  <input type="checkbox" id="checkbox" v-model="checked">
  <label for="checkbox">Checked: {\{ checked }}</label>
  <!--
    多个复选框可以绑定到
    相同的 v-model 数组
  -->
  <h2>Multi Checkbox</h2>
  <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>
  <p>Checked names: <pre>{\{ checkedNames }}</pre></p>
  <h2>Radio</h2>
  <input type="radio" id="one" value="One" v-model="picked">
  <label for="one">One</label>
  <br>
  <input type="radio" id="two" value="Two" v-model="picked">
  <label for="two">Two</label>
  <br>
  <span>Picked: {\{ picked }}</span>
  <h2>Select</h2>
  <select v-model="selected">
    <option disabled value="">Please select one</option>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <span>Selected: {\{ selected }}</span>
  <h2>Multi Select</h2>
  <select v-model="multiSelected" multiple style="width:100px">
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <span>Selected: {\{ multiSelected }}</span>
</template>