Attribute 绑定
v-bind:取值方式
开发前准备
安装node.js需要高于15.0
创建vue项目
npm init vue@latest
安装
npm install
启动
npm run dev
模板语法
文本插值 {{ 变量 }}
<p> {{ mesg }} </p>
这种方式公支持单一表达式,也可以是js代码,但是这代码需要有返回值
原始html格式 v-html
<p v-html="属性键"></p>
这个可以实现将返回的属性键值是 html 的格式下,正确解析出 html
如 键为 baidu:<a href='http://www.baidu.com'>百度</a>
刚脚本内写成
<p v-html="baidu"></p>
属性绑定
v-bind:属性名
简写方式为 :属性名,如 v-bind:id,等同于:id
双大括号不能在 html 标签的属性中使用,如果要响应式绑定,需要使用v-bind指令
即实现动态属性值
<script >
export default{
data(){
return {
dtclass:"active",
dtid:"dtid"
}
}
}
</script>
<template>
<div v-bind:id="dtid" v-bind:class="dtclass">test</div>
</template>
上述执行后,div的id和class会变成 return内的对应值
如果 dtid 的值变为null或者undefind,则在页面上会移除相应的标签
也可使用批量绑定方式,即将所有属性放到一个对象内,再通过v-bind绑定此对象
<div v-bind="obattr">test</div>
data(){
return {
obattr:{
id: "myid",
class: "myclass"
}
}
}
class属性绑定对象
用来动态显示 class 属性的属性值
可以绑定的方式有
- 对象
- 数组
- 三元运算
- 数组嵌套对象
<template>
<!-- class 绑定对象 -->
<!-- 属性值决定属性是否显示生效 -->
<!-- 即当 isActive 为ture时,则class属性值显示为 active
两个都为 ture 时,class属性值显示为 active text-danger -->
<h3 :class="{'active':isActive,'text-danger':hasError}">测试显示class属性值</h3>
<h3 :class="classObject">多个对象绑定</h3>
<!-- 这里运行后 class 的属性值为 “active text-danger a b c” -->
<h3 :class="[classObject,mylist]">数组绑定</h3>
<h3 :class="[isActive ? 'active' : '']">三元运算</h3>
</template>
<script>
export default {
data(){
return{
isActive:true,
hasError:true,
classObject:{
// 多个对象绑定时需要将这里的键与属性名一致
'active':true,
'text-danger':true
},
mylist:["a","b","c"]
}
},
methods:{
},
computed:{
}
}
</script>
<style>
.active{
color: red;
font-size: 30px;
}
</style>
style属性绑定
同class属性绑定
条件渲染
v-if 和 v-else
指令用于条件性渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染
v-else与v-if搭配使用,当不显示v-if为假时,则渲染v-else的内容
<template>
<h3>条件渲染</h3>
<div v-if="flag">你能看见我么</div>
<div v-else>那你还是看看我吧</div>
</template>
<script>
export default {
data(){
return{
flag:true
}
}
</script>
v-else-if
用于多重判断
<template>
<h3>条件渲染</h3>
<div v-if="flag">你能看见我么</div>
<div v-else>那你还是看看我吧</div>
<div v-if="num == 10">10/div>
<div v-else-if="num == 20">20</div>
<div v-else="num == 30">30/div>
</template>
<script>
export default {
data(){
return{
flag:true,
num:10
}
}
</script>
v-show
同 v-if 的应用方式,只是这里不能接 v-else
v-if 与 v-show的区别
v-if 是“真实的”按条件染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建
v-if 也是情性的:如果在初次染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。
相比之下,
v-show 简单许多,元素无论初始条件如何,始终会被染,只有 CSS display 属性会被切换.
总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始染开销。
因此,如果需要频繁切换,则使用总的来说,show 较好;
如果在运行时绑定条件很少改变,则 v-if 会更合适
列表渲染
v-for
循环新建标签,也可以用这种方式遍历对象的所有属性
<p v-for="item in items"> #这里的in可以使用of替代
{{ item }}
</p>
当遍历对象的属性时,可以使用如下获取键值
<p v-for="(value,key,index) in items"> #这里的in可以使用of替代
{{ value }},{{ key }},{{ index }}
</p>
对于json或者有嵌套的对象可以使用对象名.键名的方式调用
result:[{id:123,name:456},{id:456,name:789}]
<p v-for="item in items">
{{ item.id }}
</p>
也可以使用第二个参数,用来表示位置索引
result:[{id:123,name:456},{id:456,name:789}]
<p v-for="(item,index) in items">
{{ item.id }}{{ index }}
</p>
通过key管理状态
Vue 默认按照“就地更新”的策略来更新通过 or 染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的 key attribute:
<div v-for="item of result" :key="item.id">
温馨提示
在这里是一个通过 v-bind 绑定的特殊 attributekey推荐在任何可行的时候为 v-for 提供一个key attributekey 绑定的值期望是一个基础类型的值,例如字符串或 number 类型
事件处理
v-on:事件类型
简写为 @:数据类型
<script >
export default{
data(){
return {
count:0
}
},
methods:{
addCount(){
this.count++
}
}
}
</script>
<template>
<h3>内联事件处理器</h3>
<button @click="addCount">add</button>
<p>{{ count }}</p>
</template>
事件传参
事件参数可以获取 event 对象和通过事件传递数据
获取event对象
methods:{
addCount(e){ #这里的e就是event对象,就是js原生的event
console.log(e)
this.count++
}
}
传参则是直接在事件上传入参数
<script >
export default{
data(){
return {
count:0
}
},
methods:{
addCount(mesg){ #这里是形参
console.log(mesg)
this.count++
}
}
}
</script>
<template>
<h3>内联事件处理器</h3>
<button @click="addCount('hello')">add</button> #这里传实参
<p>{{ count }}</p>
</template>
如果要在传参的过程中还传递event参数则需要在传实参时,将envent以 $event 的方式传入
<script >
export default{
data(){
return {
count:0
}
},
methods:{
addCount(mesg,e){ #这里是形参
console.log(mesg)
console.log(e)
this.count++
}
}
}
</script>
<template>
<h3>内联事件处理器</h3>
<button @click="addCount('hello',$event)">add</button> #这里传实参
<p>{{ count }}</p>
</template>
事件修饰符
在处理事件时调用 event.preventDefaut0 或 evet.stopPropagation0 是很常见的。尽管我们可以直接在方法内调用,但如果方法能更专注于数据逻辑而不用去处理 DOM 事件的细节会更好
为解决这一问题,Vue 为 v-on 提供了事件修饰符,常用有以下几个:
- .stop
- .prevent
- .once
- .enter
调用方式
<标签名 @事件类型.事件修饰符=“xxx”>
<a @click:prevent="mymythod" href="https://baidu.com">test</a>
数组变化侦测
变更方法
Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括
push()
pop()
shift()
unshitf()
splice()
sort()
reverse()
替换数组方法
变更方法,顾名思义,就是会对调用它们的原数组进行变更。相对地,也有一些不可变(immutable) 方法,下面这些都不会更改原数组,而总是返回一个新数组。当遇到的是非变更方法时,我们需要将旧的数组替换为新的
filter()
concat()
slice()
<script >
export default{
data(){
return {
names:["a","b","c"]
}
},
methods:{
addList(){
// 这种方式直接自动更新,向原数组添加数据并显示
this.names.push("d") //变更方法
// 这种方式不会自动更新,需要手动重新赋值才能显示
this.names = this.names.concat(["f","g"])//替换数组方法
}
}
}
</script>
<template>
<button @click="addList">添加数据</button>
<ul>
<li v-for="(item,index) in names">{{ item }}</li>
</ul>
</template>
计算属性
即 computed,将复杂逻辑封闭成一个方法,放入computed标签内,在模板内直接调用方法名即可实现逻辑
<template>
<h3>测试</h3>
<p> {{ hasContent }}</p>
</template>
<script>
export default {
data(){
return {
item:{
name:"myname",
content: ["a","b"]
}
}
},
methods:{
},
// 计算属性
computed:{
hasContent(){
return this.item.content.length > 0 ? "yes" : "no"
}
}
}
</script>
与方法的区别
重点区别:
计算属性:计算属性值会基于其响应式依赖被缓存。
一个计算属性仅会在其响应式依赖更新时才重新计算方法:
方法调用总是会在重渲染发生时再次执行函数
侦听器 watch
侦听页面数据变化
只能监听 data 里面声明的数据
<template>
<h3>测试侦听器</h3>
<p>{{mesg}}</p>
<button @click="newMesg">修改数据</button>
</template>
<script>
export default {
data(){
return{
// mesg必须做为watch内的函数名
mesg:"hello"
}
},
methods:{
newMesg(){
this.mesg='update hello'
}
},
computed:{
},
watch:{
// newValue:改变之后的数据
// oldvalue: 改变之前的数据
// 函数名必须与侦听的数据对象保持一致
// 当 mesg 的值发生变化时,会自动执行这个函数
mesg(newValue,oldValue){
console.log(newValue+"===="+oldValue)
}
}
}
</script>
表单输入绑定 v-model
实时获取用户输入的数据
<template>
<h3>测试表单输入绑定</h3>
<form>
<input type="text" v-model="mesg">
<p>{{ mesg }}</p>
<input type="checkbox" id="checkbox" v-model="checked"/>
<label for="checkbox">{{ checked }}</label>
</form>
</template>
<script>
export default {
data(){
return{
mesg:"",
checked:false
}
},
methods:{
},
computed:{
}
}
</script>
三人修饰符 lazy,number,trim
lazy: 只在失去焦点的时候调用
number: 只能输入数字
trim: 去除前后空格
ref 模板引用
即使用 ref 属性来操作DOM元素
- 内容改变:模板语法{{}}
- 属性改变:v-band
- 事件绑定:@事件名或者v-on指令
如果没有特别需求,不要操作DOM
步骤是在 HTML元素中设置 ref 属性值,然后再通过 this.$refs.属性值的方式调用
<template>
<h3>测试 Ref 操作 DOM</h3>
<div ref="container" class="container">{{ container }}</div>
<button @click="getEle">getEle</button>
<!-- 这里的username供后面的 $refs 调用 -->
<input type="text" ref="username"/>
<button @click="getValue">getValue</button>
</template>
<script>
export default {
data(){
return{
container:"this is container"
}
},
methods:{
getValue(){
console.log(this.$refs.username.value)
},
getEle(){
// 使用 this.$refs.属性名的方式引用在HTML元素中ref属性指定的属性值调用
console.log(this.$refs.container)
this.$refs.container.innerHTML = "UPDATA CONT"
}
},
computed:{
}
}
</script>
组件组成
概念
Vue组件是可复用的 Vue 实例。组件是 Vue 应用程序的构建块,它们提供了一种封装 HTML、CSS 和 JavaScript 的方式,使得可以复用组件来构建复杂的界面。
其本质上是一个对象,下面的代码就是一个组件,即一个 .vue 文件,组件中 template 是必须的,其它可以不必需
<template>
<h3>测试</h3>
</template>
<script>
export default {
data(){
},
methods:{
},
computed:{
}
}
</script>
<!-- scope: 如果写了这个属性,则表示让当前样式只在当前组件中生效 -->
<style scoped>
</style>
组件最大的优势就是可复用性
当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的 we 文件中,这被叫做单文件组件(简称 SFC)
组件注册
一个组件在使用前需要被注册,分为全局注册和局部注册
全局注册
在main.js文件中操作,这种注册方式使组件在整个项目中都可用
import MyComponent from './App.vue'
app.component('MyComponent', MyComponent)
局部注册
局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用。它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好。
<script setup>
import ComponentA from './ComponentA.vue'
</script>
<template>
<ComponentA />
</template>
如果没有使用 <script setup>
,则需要使用 components
选项来显式注册:
import ComponentA from './ComponentA.js'
export default {
// 这里用于注册
components: {
ComponentA
},
setup() {
// ...
}
}
组件的引入
有四种引入方式
src属性引入
即直接将script的 src 路径设置为组件的路径
<script src="path/to/vue.js"></script>
<script src="path/to/your-component.vue"></script>
import引入
<script setup>
// RefDemo为引入名字,可以任取,一般与文件名一致
// from 后接 路径,表示组件所在的路径
import RefDemo from './components/RefDemo.vue';
</script>
<template>
<!-- 这里需要与 import 后的名称一致,才能在模板中显示 -->
<RefDemo />
</template>
路由配置引入
在Vue路由配置中通过components
属性引入:
const routes = [
{ path: '/your-route', component: YourComponent }
];
Vue.use()方法引入
在Vue插件中通过Vue.use()
方法引入:
const YourPlugin = {
install(Vue, options) {
Vue.component('your-component', YourComponent);
}
};
Vue.use(YourPlugin);
组件传递数据props
数据传递
注意事项:
传递数据,只能从父级传递到子级,不能反其道而行props,且porps只读,无法在子级中修改
步骤:
- 在父模块中引入子模块
- 在模块的中增加 <子模块名 传递的变量名1=值1,…>
- 在子模块export中增加 porps:[“变量名1”,“变量名2”,…]
- 在子模块中以 模板语法 引用变量即可
father.vue
<template>
<Child :title=title :content=content />
<div></div>
<h3>测试Props</h3>
</template>
<script >
import Child from './Child.vue';
export default {
data(){
return{
title:"Father数据",
content:"这是Fathercontent"
}
},
components:{
Child
}
}
</script>
child.vue
<template>
<h3>这是Child</h3>
<div>{{ title }}</div>
<div>{{ content }}</div>
</template>
<script>
export default {
props:["title","content"]
}
</script>
数据校验
直接在props增加以 传递数据变量为键的数据
校验类型:
- type:数据类型
- default:父组件未传递变量时子组件显示的默认值
- required:必选项,不传会发出警告
props:{
title:{
type:[String,Object,Array]
},
content:{
type:Number,
// 当父组件没有传这个变量时显示的默认值
default:0
},
// 数字和字符串可以直接default,但是如果是数组和对象,必须通过工厂函数返回默认值
names:{
type:Array,
default(){
return ["空"]
},
// 必选项
required: true
}
}
组件事件
在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件触发自定义事件的目的是组件之间传递数据
即实现子组件数据传递给父组件
步骤:
- 子组件中使用 this.$emit(方法名,参数)方式自定义一个事件
- 父组件中在引入的子组件模板内使用 @子组件方法名=“父方法名” 的方式引用
father.vue
<template>
<Child @send="getdata" />
<div></div>
<h3>测试Props</h3>
<div>{{ mesg }}</div>
</template>
<script >
import Child from './Child.vue';
export default {
data(){
return{
title:"Father数据",
content:"这是Fathercontent",
mesg:""
}
},
components:{
Child
},
methods:{
getdata(mesg){
console.log("ddddd")
this.mesg=mesg
}
}
}
</script>
Child.vue
<template>
<h3>这是Child</h3>
<button @click="sendToFather">发送数据</button>
</template>
<script>
export default {
methods:{
sendToFather(){
this.$emit("send","子组件数据")
}
}
}
</script>
插槽 Slots
元素是一个插槽出口,标示了父元素提供的插槽内容(slot content)将在哪里被渲染
步骤
- 在父组件 template 中引入模板使用 <模板名>需要传递的内容</模板名> 方式
- 在子组件 template 中增加 标签,即可在子组件中显示
渲染作用域
插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的
father.vue
<template>
<Child>
<div>11111</div>
<!-- 这里可以动态显示到子组件 -->
<h3>{{ mesg }}</h3>
<div>222222</div>
</Child>
</template>
<script >
import Child from './Child.vue';
export default {
components: {
Child
},
data() {
return {
mesg: "test"
}
}
}
</script>
child.vue
<template>
<h3>这是Child</h3>
<h3>开始引入slot</h3>
<slot></slot>
<h3>引入完成slot</h3>
</template>
<script>
</script>
默认内容
当父组件没有传递插槽给子组件时,可以在子组件child.vue中设置默认值
<template>
<h3>这是Child</h3>
<h3>开始引入slot</h3>
<slot>这里设置默认值</slot>
<h3>引入完成slot</h3>
</template>
<script>
</script>
具名插槽
即给插槽命名,方便在子组件中指定slot引入
- 在父组件template中嵌套子组件template
- 在嵌套的template中添加属性 v-slot:名称 来定义slot名称
- 在子组件中slot中添加name=名称引用插槽
v-host可以使用#代替
father.vue
<template>
<Child>
<template v-slot:one>
<div>11111</div>
<!-- 这里可以动态显示到子组件 -->
<h3>{{ mesg }}</h3>
</template>
<!-- v-slot可简写为 # -->
<template #two>
<div>222222</div>
<!-- 这里可以动态显示到子组件 -->
<h3>{{ mesg2 }}</h3>
</template>
</Child>
</template>
<script >
import Child from './Child.vue';
export default {
components: {
Child
},
data() {
return {
mesg: "第一个插槽",
mesg2: "第二个插槽"
}
}
}
</script>
child.vue
<template>
<h3>这是Child</h3>
<h3>开始引入slot</h3>
<slot name="one">默认1</slot>
<h3>引入完成slot</h3>
<slot name="two">默认2</slot>
</template>
<script>
</script>
在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽
我们也确实有办法这么做!可以像对组件传递 props 那样,向一个插槽的出口上传递attributes
组件的生命周期
每个Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码