vuejs3 第8页

Vue 3.0 组件基础

基本实例 这里有一个 Vue 组件的示例: // 创建一个Vue 应用 const app = Vue.createApp({}) // 定义一个名为 button-counter 的新全局组件 app.component('button-counter', { data() { return { count: 0 } }, template: ` <button @click="count++"> You clicked me {{ count }} times. </button>` }) INFO 在这里演示的是一个简单的示例,但是在典型的 Vue 应用程序中,我们使用单个文件组件而不是字符串模板。你可以在本节找到有关它们的更多信息。 组件是可复用的组件实例,且带有一个名字:在这个例子中是 <button-counter>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用: <div id="components-demo"> <button-counter></button-counter> </div> app.mount('#components-demo') 点击此处实现 因为组件是可复用的组件实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。 #组件的复用 你可以将组件进行任意次数的复用: <div id="components-demo"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div> 点击此处实现 注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。 #组件的组织 通常一个应用会以一棵嵌套的组件树的形式来组织 例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。 为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 component 全局注册的: const app = Vue.createApp({}) app.component('my-component-name', { // ... 选项 ... }) 全局注册的组件可以在随后创建的 app 实例模板中使用,也包括根实例组件树中的所有子组件的模板中。 到目前为止,关于组件注册你需要了解的就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把组件注册读完。 #通过 Prop 向子组件传递数据 早些时候,我们提到了创建一个博文组件的事情。问题是如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这也正是 prop 的由来。 Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中: const app = Vue.createApp({}) app.component('blog-post', {...

Vue 3.0 表单输入绑定

#基础用法 你可以用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。 提示 v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将当前活动实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。 v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件: text 和 textarea 元素使用 value property 和 input 事件; checkbox 和 radio 使用 checked property 和 change 事件; select 字段将 value 作为 prop 并将 change 作为事件。 提示 对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组织文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。 #文本 (Text) <input v-model="message" placeholder="edit me" /> <p>Message is: {{ message }}</p> 点击此处实现 #多行文本 (textarea) <span>Multiline message is:</span> <p style="white-space: pre-line;">{{ message }}</p> <br /> <textarea v-model="message" placeholder="add multiple lines"></textarea> 点击此处实现 在文本区域插值不起作用,应该使用 v-model 来代替。 <!-- bad --> <textarea>{{ text }}</textarea> <!-- good --> <textarea v-model="text"></textarea> #复选框 (Checkbox) 单个复选框,绑定到布尔值: <input type="checkbox" id="checkbox" v-model="checked" /> <label for="checkbox">{{ checked }}</label> 点击此处实现 多个复选框,绑定到同一个数组: <div id="v-model-multiple-checkboxes"> <input...

Vue 3.0 事件处理

#监听事件 我们可以使用 v-on 指令 (通常缩写为 @ 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click="methodName" 或使用快捷方式 @click="methodName" 例如: <div id="basic-event"> <button @click="counter += 1">Add 1</button> <p>The button above has been clicked {{ counter }} times.</p> </div> Vue.createApp({ data() { return { counter: 1 } } }).mount('#basic-event') 结果: 点击此处实现 #事件处理方法 然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。 例如: <div id="event-with-method"> <!-- `greet` 在下面定义的方法名 --> <button @click="greet">Greet</button> </div> Vue.createApp({ data() { return { name: 'Vue.js' } }, methods: { greet(event) { // `this` 内部 `methods` 指向当前活动实例 alert('Hello ' + this.name + '!') // `event` 是原生 DOM event if (event) { alert(event.target.tagName) } } } }).mount('#event-with-method') 结果: 点击此处实现 #内联处理器中的方法 除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法: <div id="inline-handler"> <button @click="say('hi')">Say hi</button> <button @click="say('what')">Say what</button> </div> Vue.createApp({ methods: { say(message) {...

Vue 3.0 列表渲染

#用 v-for 把一个数组对应为一组元素 我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。 <ul id="array-rendering"> <li v-for="item in items"> {{ item.message }} </li> </ul> Vue.createApp({ data() { return { items: [{ message: 'Foo' }, { message: 'Bar' }] } } }).mount('#array-rendering') 结果: 点击此处实现 在 v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。 <ul id="array-with-index"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> Vue.createApp({ data() { return { parentMessage: 'Parent', items: [{ message: 'Foo' }, { message: 'Bar' }] } } }).mount('#array-with-index') 结果: 点击此处实现 你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法: <div v-for="item of items"></div> #在 v-for 里使用对象 你也可以用 v-for 来遍历一个对象的 property。 <ul id="v-for-object" class="demo"> <li v-for="value in myObject"> {{ value }} </li>...

Vue 3.0 计算属性和侦听器

#计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如,有一个嵌套数组对象: Vue.createApp({ data() { return { author: { name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] } } } }) 我们想根据 author 是否已经有一些书来显示不同的消息 <div id="computed-basics"> <p>Has published books:</p> <span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span> </div> 此时,模板不再是简单的和声明性的。你必须先看一下它,然后才能意识到它执行的计算取决于 author.books。如果要在模板中多次包含此计算,则问题会变得更糟。 所以,对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性。 #基本例子 <div id="computed-basics"> <p>Has published books:</p> <span>{{ publishedBooksMessage }}</span> </div> Vue.createApp({ data() { return { author: { name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] } } }, computed: { // 计算属性的 getter publishedBooksMessage() { // `this` points to the vm instance return this.author.books.length > 0 ? 'Yes' : 'No' } }...

Vue 3.0 Data Property和方法

#Data Property 组件的 data 选项是一个函数。Vue 在创建新组件实例的过程中调用此函数。它应该返回一个对象,然后 Vue 会通过响应性系统将其包裹起来,并以 $data 的形式存储在组件实例中。为方便起见,该对象的任何顶级 property 也直接通过组件实例暴露出来: const app = Vue.createApp({ data() { return { count: 4 } } }) const vm = app.mount('#app') console.log(vm.$data.count) // => 4 console.log(vm.count) // => 4 // 修改 vm.count 的值也会更新 $data.count vm.count = 5 console.log(vm.$data.count) // => 5 // 反之亦然 vm.$data.count = 6 console.log(vm.count) // => 6 这些实例 property 仅在实例首次创建时被添加,所以你需要确保它们都在 data 函数返回的对象中。必要时,要对尚未提供所需值的 property 使用 null、undefined 或其他占位的值。。 直接将不包含在 data 中的新 property 添加到组件实例是可行的。但由于该 property 不在背后的响应式 $data 对象内,所以 Vue 的响应性系统不会自动跟踪它。 Vue 使用 $ 前缀通过组件实例暴露自己的内置 API。它还为内部 property 保留 _ 前缀。你应该避免使用这两个字符开头的的顶级 data property 名称。 #方法 我们用 methods 选项向组件实例添加方法,它应该是一个包含所需方法的对象: const app = Vue.createApp({ data() { return { count: 4 } }, methods: { increment() { // `this` 指向该组件实例 this.count++ } } }) const vm =...

Vue 3.0 模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层组件实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。 在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应性系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。 如果你熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量,你也可以不用模板,直接写渲染 (render) 函数,使用可选的 JSX 语法。 #插值 #文本 数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值: <span>Message: {{ msg }}</span> Mustache 标签将会被替代为对应组件实例中 msg property 的值。无论何时,绑定的组件实例上 msg property 发生了改变,插值处的内容都会更新。 通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定: <span v-once>这个将不会改变: {{ msg }}</span> #原始 HTML 双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用v-html 指令: <p>Using mustaches: {{ rawHtml }}</p> <p>Using v-html directive: <span v-html="rawHtml"></span></p> 点击此处实现 这个 span 的内容将会被替换成为 property 值 rawHtml,直接作为 HTML——会忽略解析 property 值中的数据绑定。注意,你不能使用 v-html 来复合局部模板,因为 Vue 不是基于字符串的模板引擎。反之,对于用户界面 (UI),组件更适合作为可重用和可组合的基本单位。 TIP 在你的站点上动态渲染任意的 HTML 是非常危险的,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要将用户提供的内容作为插值。 #Attribute Mustache 语法不能在 HTML attribute 中使用 ,然而,可以使用 v-bind 指令: <div v-bind:id="dynamicId"></div> 对于布尔 attribute (它们只要存在就意味着值为 true),v-bind 工作起来略有不同,在这个例子中: <button v-bind:disabled="isButtonDisabled">按钮</button> 如果 isButtonDisabled 的值是 null 或 undefined,则 disabled attribute 甚至不会被包含在渲染出来的 <button>...

Vue 3.0 响应性API Computed与watch

本节例子中代码使用的单文件组件语法 #computed 使用 getter 函数,并为从 getter 返回的值返回一个不变的响应式 ref 对象。 const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error 或者,它可以使用具有 get 和 set 函数的对象来创建可写的 ref 对象。 const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: val => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0 类型声明: // read-only function computed<T>(getter: () => T): Readonly<Ref<Readonly<T>>> // writable function computed<T>(options: { get: () => T; set: (value: T) => void }): Ref<T> #watchEffect 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。 const count = ref(0) watchEffect(() => console.log(count.value)) // -> logs 0 setTimeout(() => { count.value++ // -> logs 1 }, 100) 类型声明: function watchEffect( effect: (onInvalidate: InvalidateCbRegistrator) =>...

Vue 3.0 响应性基础 API

本节例子中代码使用的单文件组件语法 #reactive 返回对象的响应式副本 const obj = reactive({ count: 0 }) 响应式转换是“深层”的——它影响所有嵌套 property。在基于 ES2015 Proxy 的实现中,返回的代理是不等于原始对象。建议只使用响应式代理,避免依赖原始对象。 类型声明: function reactive<T extends object>(target: T): UnwrapNestedRefs<T> #readonly 获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。只读代理是深层的:访问的任何嵌套 property 也是只读的。 const original = reactive({ count: 0 }) const copy = readonly(original) watchEffect(() => { // 适用于响应性追踪 console.log(copy.count) }) // 变更original 会触发侦听器依赖副本 original.count++ // 变更副本将失败并导致警告 copy.count++ // 警告! #isProxy 检查对象是 reactive 还是 readonly创建的代理 #isReactive 检查对象是否是 reactive创建的响应式 proxy。 import { reactive, isReactive } from 'vue' export default { setup() { const state = reactive({ name: 'John' }) console.log(isReactive(state)) // -> true } } 如果 proxy 是 readonly 创建的,但还包装了由 reactive 创建的另一个 proxy,它也会返回 true。 import { reactive, isReactive, readonly } from 'vue' export default { setup() { const state = reactive({ name: 'John' })...

Vue 3.0 内置组件

#component Props: is – string | Component 用法: 渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。is 的值是一个字符串,它既可以是 HTML 标签名称也可以是组件名称。 <!-- 动态组件由 vm 实例的 `componentId` property 控制 --> <component :is="componentId"></component> <!-- 也能够渲染注册过的组件或 prop 传入的组件--> <component :is="$options.components.child"></component> <!-- 可以通过字符串引用组件 --> <component :is="condition ? 'FooComponent' : 'BarComponent'"></component> <!-- 可以用来渲染原生 HTML 元素 --> <component :is="href ? 'a' : 'span'"></component> 参考:动态组件 #transition Props: name – string 用于自动生成 CSS 过渡类名。例如:name: 'fade' 将自动拓展为 .fade-enter,.fade-enter-active 等。 appear – boolean,是否在初始渲染时使用过渡。默认为 false。 persisted – boolean。如果是 true,表示这是一个不真实插入/删除元素的转换,而是切换显示/隐藏状态。过渡钩子被注入,但渲染器将跳过。相反,自定义指令可以通过调用注入的钩子 (例如 v-show) 来控制转换。 css – boolean。是否使用 CSS 过渡类。默认为 true。如果设置为 false,将只通过组件事件触发注册的 JavaScript 钩子。 type – string。指定过渡事件类型,侦听过渡何时结束。有效值为 "transition" 和 "animation"。默认 Vue.js 将自动检测出持续时间长的为过渡事件类型。 mode – string 控制离开/进入过渡的时间序列。有效的模式有 "out-in" 和 "in-out";默认同时进行。 duration – number | { enter : number, leave : number }。指定过渡的持续时间。默认情况下,Vue 会等待过渡所在根元素的第一个 transitionend 或 animationend 事件。 enter-from-class – string leave-from-class –...