本文主要基于 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。
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> |