vue模板详解
2022年6月5日大约 6 分钟约 1870 字
简单的功能示例
<template>
<div>
<!-- html代码渲染 -->
<div v-html="titleHtml"></div>
<!-- input中双向绑定 -->
<input v-model="inputValue" type="text">
<!-- 点击事件 -->
<button v-on:click="addItemHandle">增加</button>
<button v-on:click="showHandle">显示/隐藏</button>
<!-- 条件判断来显示隐藏元素 -->
<ul v-if="show">
<!-- 循环的使用,插值表达式的使用 -->
<li v-for="(item, index) of list">{{index}}. {{ item }}</li>
</ul>
<!-- 非响应式,变量仅使用一次,后面不再跟随变化 -->
<div v-once>{{footer}}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// html代码渲染
const titleHtml = ref('<h1>todo list示例</h1>')
// 添加输入项的功能
const inputValue = ref('')
const list = ref(['hello', 'world', 'tom', 'sun'])
const addItemHandle = () => {
list.value.push(inputValue.value)
inputValue.value = ''
}
// 显示隐藏的功能
const show = ref(true)
const showHandle = () => {
show.value = !show.value
}
// 页脚的内容
const footer = ref('示例结束')
setTimeout(()=>{ footer.value = '示例继续?'}, 3000)
</script>
提示
v-on:
的简写是@
v-bind:
的简写是:
v-bind 绑定元素属性
v-bind的动态属性
<template>
<!-- 属性名也可以用变量(动态属性) -->
<div :[name]="nameValue"></div>
</template>
<script setup>
import { ref } from 'vue'
const name = ref('title')
const nameValue = ref('标题1')
</script>
绑定样式
<template>
<div :class="classString" class="font-size: 20px;">文本1</div>
<div :class="classObject">文本1</div>
<div :class="classArray">文本2</div>
<div :style="styleString">文本3</div>
<div :style="styleObject">文本3</div>
</template>
<script setup>
import { ref } from 'vue'
// class类
const classString = ref('red')
const classObject = ref({ red: true, bgGreen: true })
const classArray = ref(['green', 'bgRed', { border: true }])
// 行类style
const styleString = ref('color: yellow;')
const styleObject = ref({ color: 'orange' }) // 推荐
</script>
<style lang="scss" scoped>
.red { color: red; }
.green { color: green; }
.bg-red { background-color: red; }
.bg-green { background-color: green; }
.border { border: 2px solid; }
</style>
:class
和class
可以同时使用
子组件传递样式
子组件仅有一个根元素时
<template>
<demo class="red"></demo>
</template>
<script setup>
import { ref } from 'vue'
const classString = ref('red')
</script>
<style lang="scss" scoped>
.red { color: red; }
</style>
子组件有多个根元素时
<!-- 当有多个根元素时,子组件并不知道父组件传递过来的样式放到哪个根元素,这里就需要在子组件中进行明示 -->
<!-- 以下是子组件的配置 -->
<template>
<!-- 将父组件传递过来的class进行显式绑定 -->
<div :class="$attrs.class">one</div>
<!-- 也可以直接在子组件写样式 -->
<div class="green">two</div>
</template>
if判断
<template>
<div v-show="show">hello world</div>
<!-- 提示: 下面三个元素需要相连才有效 -->
<div v-if="conditionOne">if</div>
<div v-else-if="conditionTwo">else-if</div>
<div v-else>else</div>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(false)
const conditionOne = ref(false)
const conditionTwo = ref(true)
</script>
注意
v-if
和v-show
功能类似,唯一区别是:
v-if
为false时,会把整个元素销毁,从DOM中消失v-show
为false时,仅仅是元素display: none;
,元素仅看不见但还在DOM中
所以,频繁改变元素显示建议使用v-show,性能成本好
循环
<template>
<!--列表循环方法一:-->
<div v-for="item in myArray" :key="item"> {{ item }} </div>
<!--列表循环方法二:-->
<div v-for="(item, index) in myArray" :key="item">{{index}}. {{ item }} </div>
<!-- 对象循环方法一:后面的参数也可以省略 -->
<div v-for="(value, key, index) in myObject" :key="key">{{index}}. {{key}}: {{ value }} </div>
</template>
<script setup>
import { ref } from 'vue'
const myArray = ref(['tom', 'sun', 'sunny'])
const myObject = ref({ name: 'tom', age: 22, sex: '男', job: 'teacher' })
</script>
key值
循环中的key
值是为了优化渲染性能,循环中没有变化的数据在新渲染中再次复用
key
里面的值是必须唯一的
循环与判断
尽量不要把循环语句和判断语句写到一起,循环优先级高于判断,可能会逻辑混淆出错
可以将if拆到子元素写,父元素用template标签
事件
传递参数
默认传递event
<template>
<div>
{{counter}}
<button @click="btnClickHandle">按钮</button>
</div>
</template>
<script setup>
const counter = ref(0)
// 原生事件event默认会被传进来
const btnClickHandle = (event) => {
console.log(event.target)
counter.value++
}
</script>
传递自定义参数
<template>
<div>
{{counter}}
<!-- 如果需要传递原生事件,需要显式传递过去 -->
<button @click="btnClickHandle(10, $event)">按钮</button>
</div>
</template>
<script setup>
const counter = ref(0)
// 原生事件event默认会被传进来
const btnClickHandle = (num, event) => {
console.log(event.target)
counter.value += num
}
</script>
同时绑定多个处理函数
<template>
<div>
{{counter}}
<!-- 这里需要给函数加括号 -->
<button @click="btnClickHandle1(), btnClickHandle2()">按钮</button>
</div>
</template>
<script setup>
const btnClickHandle1 = () => { alert('btnClickHandle1') }
const btnClickHandle2 = () => { alert('btnClickHandle1') }
</script>
事件的动态属性
<template>
<!-- 属性名也可以用变量(动态属性) -->
<div @[eventName]="eventHandle"></div>
</template>
<script setup>
import { ref } from 'vue'
const eventName = ref('click')
const eventHandle = () => {
}
</script>
事件修饰符
阻止默认行为
.prevent
修饰符
<template>
<div>
<!-- 阻止事件默认行为 -->
<form action="https://www.baidu.com" @click.prevent="clickHandle"></form>
</div>
</template>
<script setup>
import { ref } from 'vue'
const clickHandle = () => {
alert('click')
}
</script>
阻止冒泡
.stop
修饰符
<template>
<div @click="divClickHandle">
<button @click.stop="btnClickHandle">按钮</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const divClickHandle = () => { alert('divClick') }
const btnClickHandle = () => { alert('btnClick') }
</script>
如果不加.stop
修饰符,当点击按钮时,按钮点击事件默认会冒泡到上层Div点击事件,两个点击处理函数都会激活
仅自己触发
.self
修饰符
<template>
<div @click.self="divClickHandle">
div内容
<button @click="btnClickHandle">btn按钮</button>
</div>
</template>
<script setup>
const divClickHandle = () => { alert('divClick') }
const btnClickHandle = () => { alert('btnClick') }
</script>
div的点击事件只能点击div内容
时触发,点击子元素都无法触发,只能由自己才能触发
仅能执行一次
.once
修饰符
<template>
<button @click.once="btnClickHandle">btn按钮</button>
</template>
<script setup>
const btnClickHandle = () => { alert('btnClick') }
</script>
该事件仅能触发一次
按键和鼠标修饰符
按键
<template>
<input @keydown.enter="keyDownHandle" type="text">
</template>
<script setup>
const keyDownHandle = () => { console.log('Enter') }
</script>
仅按下回车时触发
相关类似按键
delete
tab
sec
up
down
left
right
鼠标
<template>
<button @click.right="clickHandle"></button>
</template>
<script setup>
const clickHandle = () => { console.log('右键点击') }
</script>
右键点击时触发
相关类似
left
right
middle
ctrl
.ctrl
:按住ctrl键点击
.ctrl.exact
:精确按住ctrl键点击。按ctrl同时还按其他键再点击是无效的
表单双向绑定
示例
<template>
<!-- 输入框的value属性就不用写了 -->
<input v-model="message" type="text"><br>
<textarea v-model="message" /><br>
<!-- 默认值是布尔值,这里改为其他值 -->
张三 <input type="checkbox" v-model="nameArray" value="张三">
李四 <input type="checkbox" v-model="nameArray" value="李四"><br>
<!-- 自定义value -->
吃饭没?<input type="checkbox" v-model="eatString" true-value="吃了" false-value="没吃"><br>
赵云 <input type="radio" v-model="radioString" value="赵云">
张飞 <input type="radio" v-model="radioString" value="张飞"><br>
<!-- 如果配置multiple可多选,v-model建议给个数组 -->
<select v-model="selectString">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('hello')
const nameArray = ref([ '三毛' ])
const eatString = ref('')
const radioString = ref('')
const selectString = ref('C')
</script>
修饰符
<template>
{{ message }}
<!-- lazy懒加载,等输入框失去焦点才更新数据 -->
lazy修饰符:<input type="text" v-model.lazy="message"><br>
<!-- 存储数据时,自动转为数值类型存储 -->
number修饰符:<input type="text" v-model.number="number"><br>
<!-- 存储时自动删除两边空格 -->
trim修饰符:<input type="text" v-model.trim="message"><br>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('')
const number = ref(0)
</script>
获取dom元素节点
<template>
<div>
<div ref="hello">Hello World</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const hello = ref(null) // 变量名需等于模板中ref属性名
onMounted(()=>{
console.log('验证结果:', hello.value)
})
</script>
注意
模板中的ref属性和script中的响应式引用ref完全不是一回事,只是名字一样。
模板中ref属性是指dom元素节点引用,script中ref包裹是指响应式变量引用,完全不是一回事。