一、模板语法
文本
数据绑定最常见的形式就是使用“Mustache”(双大括号)语法的文本插值
<span>Message:{{ msg }}</span>
一般配合js 中的 data() 设置数据
export default {
name: "HelloWorld",
data(){
return{
msg: "消息提示"
}
}
}
原始 HTML
双大括号会将数据解释为普通文本,而非HTML代码。为了输出真正的 HTML ,需要使用 v-html 指令
<p>Using mustaches:{{ rawHtml }}</p>
<p>Using v-html directive:<span v-html="rawHtml"></span></p>
data(){
return{
rawHtml: "<a href="https://www.baidu.com">百度</a>"
}
}
属性 Attribute
Mustache 语法不能在 HTML 属性中使用,然而,可以使用 v-bind 指令。
<div v-bind:id="dynamicId"></div>
data(){
return{
dynamicId: 1001
}
}
提示:
v-bind 指令可以进行简写,如 v-bind:id=“dynamicId” 可以简写成 :id=“dynamicId”。
JavaScript 表达式
刚才的模板中,我们一直都只绑定简单的 property 键值,实际 Vue.js 提供了完全的 JavaScript 表达式支持
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
每个绑定都只能包含单个表达式,举例一些不会生效的例子(错误示范):
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流程控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
二、条件渲染
v-if
v-if 指令用于条件性地渲染一块内容,这块内容只会在指令的表达式返回 true 值的时候被渲染。
<p v-if="flag">我是孙猴子</p>
data(){
return {
flag: true
}
}
v-else
可以使用 v-else 指令来表示 v-if 的“else 块”
<p v-if=“flag”>我是孙猴子</p>
<p v-else>你是傻猴子</p>
data(){
return {
flag: false
}
}
v-show
另一个用于条件性展示元素的选项是 v-show 指令
<h1 v-show="ok">Hello!</h1>
v-if 和 v-show 的区别:
v-if 是“真正”的条件渲染,应为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 是惰性的;如果在初始渲染时条件为假,则什么也不做,知道条件第一次变为真时,他才会开始渲染条件块。
相比之下,v-show 就简单多,不管初始条件是否成立,元素都会被渲染,并且只是简单地基于CSS进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。说人话就是,如果模块需要频繁地切换,推荐用 v-show;如果运行时条件很少改变,则使用 v-if 较好。
三、列表渲染
用 v-for 把一个数组映射为一组元素
我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。
<ul>
<li v-for="item in items">{{ item.message }}</li>
</ul>
data(){
return {
items: [{ message: 'Foo' },{ message: 'Bar' }]
}
}
维护状态
当 Vue 正在更新使用 v-for 渲染元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变了,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保他们在每个索引位置正确渲染。
为了给Vue 一个提示,以便它跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的 key attrubute:
<div v-for="(item,index) in items" :key="item.id">
<!-- 内容 -->
</div>
或者
<div v-for="(item,index) in items" :key="index">
<!-- 内容 -->
</div>
效果演示:
未加key的v-for,删除的元素时会出现一些问题。
上图中,仔细看,可以看出这是在第一个li上直接更新的,也就是复用了第一个li的DOM结构,也就是直接在第一个li上改成了第二个li(观察对应的class和li前面的数字)。
为解决这个问题,vue推荐我们使用索引,使用索引后的效果如下:
四、事件处理
监听事件
我们可以使用 v-on 指令(通常缩写为 @ 符号)来监听 DOM 事件,并在触发事件时执行一些JavaScript。用法为:v-on:click=“methodName” 或使用快捷方式 @click=“methodName” 。
<button @click="counter += 1">
Add 1
</button>
data(){
return {
counter: 0
}
}
通常情况下,我们是不推荐直接在事件绑定中直接写内容的,因为许多事件处理逻辑更为复杂,直接将 js 代码写在 v-on 指令中不可行。推荐使用 v-on 接收方法名的方式来完成该操作。
<button @click="greet">
Greet
</button>
methods: {
greet(event){
// 'event'是原生的 DOM event
if(event){
alert(event.target.tagName)
}
}
}
示例:
方法事件中也可以进行参数传递,官方成为“内联处理器中的方法”。
<button @click="say('hi')">Say hi</button>
<button @click="say('what')">Say what</button>
methods: {
say(message) {
alert(message)
}
}
五、表单输入绑定
可以利用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖(更简单的写法)。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。
<input v-model="message" placeholder="edit me">
<p>Message is:{{ message }}</p>
data() {
return {
message: ""
}
}
修饰符
- .lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步。
<input v-model.lazy="message"/>
<p>Message is:{{ message }}</p>
data() {
return {
message: ""
}
}
- .trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符。
<input v-model.trim="message" />
data() {
return {
message: ""
}
}
6、组件基础
单文件组件
Vue 单文件组件(又名为 *.vue 文件,缩写为 SFC)是一种特殊的文件格式,它允许将 Vue 组件的模板、逻辑 与 样式 封装在单个文件中。
<template>
<h3>
单文件组件
</h3>
</template>
<script>
export default {
name: "MyComponent"
}
</script>
<!-- scoped:如果在style中添加此属性,就代表着当前样式,只在当前组件中生效 -->
<style scoped>
h3{
color: red;
}
</style>
加载组件
- 第一步:引入组件 import MyComponentVue from ‘./components/MyComponent.vue’
- 第二步:挂载组件 components: {MyComponentVue}
- 第三步:显示组件 <my-componentVue/>
每个.vue文件都是个组件,可以嵌入其他的.vue文件中,形成一个组件树。
7、props的组件交互
组件与组件之间是存在交互的,存在交互才有意义。
Prop 是你可以再组件上注册的一些自定义 attribute。
<my-componentVue title="标题"/>
<template>
<h3>单文件组件</h3>
<p>{{ title }}</p>
</template>
<sctipt>
export default {
name: "MyComponent",
props: {
title:{
type: String,
default: ""
}
}
}
</sctipt>
Prop 类型
Prop传递参数没有限制,常见有的以下这些:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function
}
注意: 当数据类型为数组或者对象的时候,默认值是需要返回工厂模式(工厂模式可以理解为,将响应封装成函数进行返回)。
演示
结合第6点组件基础和第7点组件交互,做个实例演示。
问题: 定义两个组件,一个用于展示数据,一个用于获取数据,通过加载组件的方式关联起来。
思路: 编写两个vue文件,一个是People.vue,表示为人的模板;另一个是Introduce.vue,表示介绍信息,该文件能获取到人的描述信息。需要将People.vue 和 Introduce.vue 关联起来,最终在App.vue中引用。
People.vue
<template>
<div v-for="(item,index) in objectArray" :key="index">
<p>姓名:{{ item.name }} 年龄:{{ item.age }}</p>
<p>性格:
<ul >
<li v-for="(item1,index) in item.character" :key="index">{{ item1 }}、</li>
</ul>
</p>
</div>
<div>
<p>姓名:{{ man.name }} 年龄:{{ man.age }}</p>
<p>性格:
<ul>
<li v-for="item2 in man.character" :key="man.name">{{ item2 }}</li>
</ul>
</p>
</div>
<div>
<p>姓名:{{ name }} 年龄:{{ age }}</p>
<p>性格:
<ul>
<li v-for="item3 in character" :key="name">{{ item3 }}</li>
</ul>
</p>
</div>
</template>
<script>
export default{
name: 'People',
props:{
//数组(数组里存放的是对象)
objectArray:{
type: Array,
default: function(){
return []
}
},
//对象
man:{
type: Object,
default: function(){
return {}
}
},
//字符串
name:{
type: String,
required: true,
default: ""
},
//数字
age:{
type: Number,
default: 0
},
//数组
character:{
type: Array,
default: function(){
return [];
}
}
}
}
</script>
<style></style>
Introduce.vue
<template>
<p>this is Introduce.vue</p>
<People :objectArray="objectArray" :man="man" :name="name" :age="age" :character="character"/>
</template>
<script>
import People from './People.vue'
export default{
name: 'Introduce',
data(){
return{
objectArray: [
{
name: "张三",
age: 18,
character: ["傲慢","易怒","猜疑"]
},
{
name: "李四",
age: 23,
character: ["谦虚","和蔼","信任"]
}
],
man: {
name: "王五",
age: 26,
character: ["佛系","随和","孤僻"]
},
name: "赵六",
age: 30,
character: ["狡诈","恶毒","圆滑"]
}
},
components:{
People
}
}
</script>
<style></style>
App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<Introduce/>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import People from './components/People.vue'
import Introduce from './components/Introduce.vue'
export default {
name: 'App',
components: {
HelloWorld,
People,
Introduce
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 40px;
}
</style>
8、自定义事件组件交互
自定义事件可以在组件中反向传递数据,prop 可以将数据从父组件传递到子组件,那么反向操作就可以利用自定义事件实现 Semit 。
MyComponent.vue
<template>
<h3>单文件组件</h3>
<button @click="sendHandle">发送数据</button>
</template>
<script>
export default{
name: "MyComponent",
methods:{
sendHandle(){
this.$emit("onCustom","你好呀!")
}
}
}
</script>
<style></style>
App.vue
<template>
<MyComponent @onCustom="getData"></MyComponent>
</template>
<script>
import MyComponent from './components/MyComponent.vue'
export default {
name: 'App',
components: {
MyComponent
},
methods:{
getData(data){
console.log(data);
}
}
}
</script>
子组件向父组件发送数据,效果如下:
9、组件的生命周期
重点:需要理解透彻。
为了方便记忆,我们可以将他们分类:
创建时:beforeCreate 、created
渲染时:beforeMount 、mounted
更新时:beforeUpdate 、update
卸载时:beforeUnmount 、unmount
使用场景举例:
接口请求时,放在生命周期mounted中。
评论区