see:https://github.com/hi-cooper/vue-learning.git
途径:
**Element Text:**双大括号模板{{ <变量/函数/简单js表达式>}}
Element Attribute:[v-bind]:attribute
**Element Event:**v-on:event(简写@event)
- 支持简单表达式(即有唯一的return值)
- 响应式:不监听普通js变量,仅监听ref、reactive变更,当ref/reactive变量值变化时,会重新渲染组件。
ref、reactive、toRef、toRefs区别:
- **ref:**支持任何类型。包含基本数据类型、对象类型(如深层嵌套对象、简单对象、数组等)。非基本类型将通过 reactive() 转换为响应式代理。基本数据类型时推荐使用
- **reactive:**仅支持对象类型,不支持基本数据类型。对象类型时推荐使用。
- **toRef():**可以为传入对象的某个属性新创建一个响应式引用 ref。这个 ref 可以被传递,它会保持对其源 property 的响应式连接。修改响应式数据会影响以前的数据;数据改变,界面不自动更新
- toRefs():(1)接收一个对象作为参数,它会遍历对象身上所有属性,然后调用单个toRef
(2)将对象的多个属性变成响应式数据,并且要求响应式数据和原始数据关联,且更新响应式数据的时候不会更新界面,用于批量设置多个数据为响应式
1 Element text 绑定 JS变量/函数:双大括号模板
格式:
{{ <变量/函数/简单js表达式> }}
限制:不允许在HTML attributes 中使用
<script setup lang="ts">
import { reactive, ref } from 'vue';
const refState1 = ref(1); // OK
const refState2 = ref({ count: 2 }); // OK
// const reactiveState1 = reactive(3); // NOT OK
const reactiveState2 = reactive({ count: 4 }); // OK
console.log(refState1.value); // 1
console.log(refState2.value.count); // 2
console.log(reactiveState2.count); // 4
function sayHelloRefState1(msg: string): string {
return msg + refState1.value;
}
</script>
<template>
refState1 = {{ refState1 }}<br />
refState2 = {{ refState2 }}<br />
refState2.count = {{ refState2.count }}<br />
reactiveState2 = {{ reactiveState2 }}<br />
reactiveState2.count = {{ reactiveState2.count }}<br />
{{ sayHelloRefState1('hello, ') }}<br />
</template>
结果
2 Element attribute 绑定 JS变量/函数:v-bind/v-model
v-bind:单向绑定。用于绑定数据、属性、表达式。简写
:<attribute>
v-mode:双向绑定。用于form表单中,在form外使用不起作用
2.1 带attribute的v-bind
<script setup lang="ts">
import { reactive } from 'vue';
const reactiveState2 = reactive({ count: 4 }); // OK
function sayHello(msg: string): string {
return msg + reactiveState2.count;
}
</script>
<template>
v-bind方式:<input v-bind:value="reactiveState2.count" /><br />
简写方式:<input :value="reactiveState2.count" /><br />
绑定函数:<input :value="sayHello('hello, ')" />
</template>
结果
2.2 不带attribute的v-bind
<script setup lang="ts">
const objectOfAttrs = {
id: 'container',
class: 'wrapper'
}
</script>
<template>
<div v-bind="objectOfAttrs"></div>
</template>
结果
<div id="container" class="wrapper"></div>
3 Element event 绑定 JS函数
<script setup lang="ts">
import { reactive } from 'vue';
const reactiveState2 = reactive({ count: 4 }); // OK
function count(): void {
reactiveState2.count++;
}
function countWith(val: number): void {
reactiveState2.count += val;
}
function countWithEvent(val: number, event: MouseEvent): void {
reactiveState2.count += val;
const target = event.target as HTMLButtonElement;
console.log(target.id);
}
</script>
<template>
<button v-on:click="count">使用v-on</button>
<button @click="count">使用@</button>
<button @click="countWith(4)">带参数</button>
<button id="ID_A" @click="countWithEvent(5, $event)">带参数和事件1</button>
<button id="ID_B" @click="countWithEvent(100, $event)">带参数和事件2</button><br />
{{ reactiveState2.count }}
</template>
4 综合示例
<template>
<!-- 绑定事件 -->
<button
@click="changePlainStateOnly"
title="只更新普通变量,不会重新渲染组件(即界面上的普通变量不会更新)"
>
Change PlainState Only
</button>
<button
@click="changeAllState"
title="更新带ref/reactive变量,会重新渲染组件(所以普通变量也会在界面中刷新)"
>
Change All State
</button>
<button
@click="changeToRefState"
title="更新toRef变量,会重新渲染组件,同时影响toRef变量,以及它所指向的ref/reactive变量"
>
Change toRef State
</button>
<button @click="changeToRefsStateDemo1" title="同toRef">Change toRefs State (Demo1)</button>
<button @click="changeToRefsStateDemo2" title="同toRef">Change toRefs State (Demo2)</button><br />
<div class="demo ok-demo">正确示例</div>
<div class="demo-child">
<div class="category">
<span class="title">Element text 绑定 JS变量</span>
<ul>
<li>refState1 = {{ refState1 }}</li>
<li>toRefState1 (refState1) = {{ toRefState1 }}</li>
<li>---</li>
<li>refState2.count = {{ refState2.count }}</li>
<li>toRefState2 (refState2.count) = {{ toRefState2 }}</li>
<li>toRefsState2 (refState2) = {{ toRefsState2.count }}</li>
<li>count (refState2.count) = {{ count }}</li>
<li>name (refState2.name) = {{ name }}</li>
<li>---</li>
<li>reactiveState1.count = {{ reactiveState1.count }}</li>
<li>toRefState3 (reactiveState1.count) = {{ toRefState3 }}</li>
<li>toRefsState3 (reactiveState1) = {{ toRefsState3.count }}</li>
<li>
reactiveState1Count (reactiveState1.reactiveState1Count) = {{ reactiveState1Count }}
</li>
<li>reactiveState1Name (reactiveState1.reactiveState1Name) = {{ reactiveState1Name }}</li>
</ul>
</div>
<div class="category">
<span class="title">Element attribute 绑定 JS变量</span>
<ul>
<li title="使用:简写">refState1: <input :value="refState1" /></li>
<li title="使用 v-bind">refState1 (v-bind): <input v-bind:value="refState1" /></li>
<li>refState2.count: <input :value="refState2.count" /></li>
</ul>
</div>
<div class="category">
<span class="title">仅支持简单表达式</span>
<ul>
<li>
<input :value="'count=' + refState1" />
</li>
<li><input :value="refState1 + 100" /></li>
</ul>
</div>
<div class="category">
<span class="title">Element text/attribute 绑定 JS函数</span>
<div :title="getConcatCount('hello, ')">
{{ getConcatCount('hello, this count =') }}
</div>
</div>
<div class="category">
<span class="title">绑定包含多个 attribute 的 JS变量</span>
<div v-bind="objectOfAttrs"></div>
</div>
</div>
<div class="demo error-demo">错误示例</div>
<div class="demo-child">
<!-- attribute中不支持{{ }},需使用v-bind -->
<div class="category">
<ul>
<li>plainState1:{{ plainState1 }}</li>
<li>plainState1: <input type="text" :value="plainState1" /></li>
<li>plainState2.count: <input type="text" :value="plainState2.count" /></li>
<li>
<input value="{{ plainState1 }}" /><span class="red">无效:不允许绑定HTML attribute</span>
</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, toRef, toRefs, onMounted, type Ref, type UnwrapNestedRefs } from 'vue';
import init from '@/global';
var plainState1 = 1000;
const plainState2 = {
count: 2000,
name: 'plainState2',
plainState2Name: 'plainState2',
plainState2Count: 2000
};
const refState1 = ref(3000);
const refState2 = ref({
count: 4000,
name: 'refState2'
});
const reactiveState1 = reactive({
count: 5000,
name: 'reactiveState1',
reactiveState1Name: 'reactiveState1',
reactiveState1Count: 5000
});
var toRefState1 = toRef(refState1);
var toRefState2 = toRef(refState2.value, 'count');
var toRefState3 = toRef(reactiveState1, 'count');
// const toRefsState1 = toRefs(refState1); // ERROR, could not read value
// const toRefsState1 = toRefs(refState2); // ERROR, could not read value
const toRefsState2 = toRefs(refState2.value);
const toRefsState3 = toRefs(reactiveState1);
var { name, count } = toRefs(refState2.value);
var { reactiveState1Name, reactiveState1Count } = toRefs(reactiveState1);
function changePlainStateOnly() {
plainState1++; // 不会更新界面
plainState2.count++; // 不会更新界面
}
function changeAllState() {
plainState1++; // 会更新界面,因后面包含ref/reactive变量,会重新刷新组件
plainState2.count++; // 会更新界面,因后面包含ref/reactive变量,会重新刷新组件
refState1.value++; // 同时会更新界面(refState1、toRefState1、toRefsState1)
refState2.value.count++; // 同时会更新界面(refState2、toRefState2、toRefsState2、name、 count)
reactiveState1.count++; // 同时会更新界面(reactiveState1、toRefState3、toRefsState3)
}
function changeToRefState() {
toRefState1.value++; // 同时会更新界面(refState1、toRefState1、toRefsState1)
toRefState2.value++; // 同时会更新界面(refState2、toRefState2、toRefsState2、name、 count)
toRefState3.value++; // 同时会更新界面(reactiveState1、toRefState3、toRefsState3)
}
function changeToRefsStateDemo1() {
// toRefsState1++; // 同时会更新界面(refState1、toRefState1、toRefsState1)
toRefsState2.count.value++; // 同时会更新界面(refState2、toRefState2、toRefsState2、name、 count)
toRefsState3.count.value++; // 同时会更新界面(reactiveState1、toRefState3、toRefsState3)
}
function changeToRefsStateDemo2() {
count.value++; // 同时会更新界面(refState2、toRefState2、toRefsState2、name、 count)
reactiveState1Count.value++; // 同时会更新界面(reactiveState1.reactiveState1Count)
}
function getConcatCount(msg: string): string {
return msg + ' ' + refState1.value;
}
onMounted(() => {
console.log(`The initial refState1 is ${refState1.value}.`);
init();
});
const objectOfAttrs = {
id: 'container',
class: 'wrapper',
style: 'width: 500px; height: 50px; background-color: #00eeee;'
};
</script>