在上一节中写了条件,列表渲染和事件的绑定,vue的事件绑定结合修饰符的使用,相比Jquery时代,极大的简化了事件相关的操作。下面继续来看vue的表单输入绑定和组件基础,也是vue基础内容的最后一节。
一、表单输入绑定
用 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
作为事件。
多个复选框,绑定到同一个数组:
1 <div id="v-model-multiple-checkboxes"> 2 <input type="checkbox" id="jack" value="Jack" v-model="checkedNames" /> 3 <label for="jack">Jack</label> 4 <input type="checkbox" id="john" value="John" v-model="checkedNames" /> 5 <label for="john">John</label> 6 <input type="checkbox" id="mike" value="Mike" v-model="checkedNames" /> 7 <label for="mike">Mike</label> 8 <br /> 9 <span>Checked names: {{ checkedNames }}</span> 10 </div>
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步。你可以添加 lazy
修饰符,从而转为在 change
事件_之后_进行同步:
1 <!-- 在“change”时而非“input”时更新 --> 2 <input v-model.lazy="msg" />
.number:
自动将用户的输入值转为数值类型,可以给
v-model
添加 number。
.trim:自动过滤用户输入的首尾空白字符。
二、组件基础
组件是带有名称的可复用实例。看一个组合示例:
1 <template> 2 <li>{{ todo.text }}</li> 3 </template> 4 <script> 5 export default { 6 name: "todo-item", 7 props: ["todo"], 8 }; 9 </script>
因为组件是可复用的组件实例,所以它们与根实例接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。可以将组件进行任意次数的复用:
1 <template> 2 <div> 3 <ol> 4 <todo-item v-for="item in list" v-bind:todo="item" v-bind:key="item.id"></todo-item> 5 <todo-item v-for="item in list" v-bind:todo="item" v-bind:key="item.id"></todo-item> 6 <todo-item v-for="item in list" v-bind:todo="item" v-bind:key="item.id"></todo-item> 7 <todo-item v-for="item in list" v-bind:todo="item" v-bind:key="item.id"></todo-item> 8 </ol> 9 </div> 10 </template> 11 <script> 12 import TodoItem from "./TodoItem.vue"; 13 export default { 14 name: "Test", 15 components: { 16 TodoItem, 17 }, 18 data() { 19 return { 20 message: "safsadf", 21 list: [ 22 { id: 0, text: "Vegetables" }, 23 { id: 1, text: "Cheese" }, 24 { id: 2, text: "Whatever else humans are supposed to eat" }, 25 ], 26 }; 27 } 28 }; 29 </script>
注意当循环遍历时,每个组件都会各自独立维护它的 item
。因为你每用一次组件,就会有一个它的新实例被创建。
通常一个应用会以一棵嵌套的组件树的形式来组织。例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。
Prop 是你可以在组件上注册的一些自定义 attribute。如上面的 props: ["todo"]。当一个值被传递给一个 prop attribute 时,它就成为该组件实例中的一个 property。该 property 的值可以在模板中访问,就像任何其他组件 property 一样。一个组件默认可以拥有任意数量的 prop,无论任何值都可以传递给 prop。
监听子组件事件
一些功能可能需要与父级组件进行沟通。例如我们可能会引入一个辅助功能来放大博文的字号,同时让页面的其它部分保持默认的字号:
1 <template> 2 <li :style="{fontSize:size+'em'}">{{ todo.text }} <button @click="$emit('enlargeText')">放大字体</button></li> 3 </template> 4 <script> 5 export default { 6 name: "todo-item", 7 props: ["todo",'size'], 8 emits:['enlargeText'] 9 }; 10 </script>
从示例中,通过添加一个按钮,再通过$emit定义一个事件 enlargeText 暴露出去,在引用的地方进行调用。同时再定义一个变量 size ,供外部传值:
1 <template> 2 <div> 3 <ol> 4 <todo-item 5 v-for="item in list" 6 :todo="item" 7 :key="item.id" 8 :size="size" 9 @enlargeText="onEnlargeText" 10 ></todo-item> 11 </ol> 12 </div> 13 </template> 14 <script> 15 import TodoItem from "./TodoItem.vue"; 16 export default { 17 name: "Test", 18 components: { 19 TodoItem, 20 }, 21 data() { 22 return { 23 message: "safsadf", 24 size: 1, 25 list: [ 26 { id: 0, text: "Vegetables" }, 27 { id: 1, text: "Cheese" }, 28 { id: 2, text: "Whatever else humans are supposed to eat" }, 29 ], 30 }; 31 }, 32 methods: { 33 onEnlargeText() { 34 this.size += 1; 35 }, 36 }, 37 }; 38 </script>
动态组件
有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里。
1 <!-- 组件会在 `currentTabComponent` 改变时改变 --> 2 <component :is="currentTabComponent"></component>
其中currentTabComponent 是计算属性,component 相当于是一个占位符,currentTabComponent 计算出哪个组件名,DOM就会展现哪个组件。
有些 HTML 元素,诸如 <ul>
、<ol>
、<table>
和 <select>
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>
、<tr>
和 <option>
,只能出现在其它某些特定的元素内部。比如以下示例:
1 <!-- 这样会报错 --> 2 <table> 3 <blog-post-row></blog-post-row> 4 </table> 5 6 <!-- 可以这样解决 --> 7 <table> 8 <tr v-is="'blog-post-row'"></tr> 9 </table>
v-is
值应为 JavaScript 字符串文本