一、指令
1.内容渲染指令
a.v-text
b.{{}}
c.v-html
<body>
<div>
<p v-text='name'></p> //zh
<p>年龄:{{age}}</p> //年龄:18
<p v-text='gender'>性别</p> //男,v-text会覆盖“性别”
<p v-html='desc'></p> //打印斜体,识别HTML标签
</div>
</body>
const vm =new vue({
el:'#app',
data:{
name:'zh',
age:18,
gender:'男'
desc:'<i>江山如此多娇</i>'
}
})
2.属性绑定指令
a.v-bind 省略写法为“:”
<body>
<div>
<input type='text' v-bind:placeholder='pinput'>
//省略写法
<input type='text' :placeholder='pinput'>
<a :href='asrc'>
</div>
</body>
const vm =new vue({
el:'#app',
data:{
pinput:"请输入名称",
asrc:“https://www.baidu.com”
}
})
注:vue提供的模板渲染语法中,不仅能够进行简单的数据绑定,还能够进行js表达式运算
<body>
<div>
<p>{{name === 'zh'?zh:'未知'}}</p> //未知
<p>年龄:{{age + 1 }}</p> //19
<p v-text='gender'>性别</p>
<p v-html='desc'></p>
</div>
</body>
const vm =new vue({
el:'#app',
data:{
name:'zc',
age:18,
gender:'男'
}
})
3.事件绑定指令
a.v-on.事件处理函数写在methods节点中。简写形式为“@”
<body>
//绑定事件
<div>现在数值为:{{count}}</div>
<button v-on:cilck="addCount">+1</button> //点击后count自增1,背景颜色为红
</body>
const vm =new vue({
el:'#app',
data:{
count:0
},
methods:{
//事件处理函数
addCount(e){
this.count +=1,
e.target.style.backgroundColor= red
}
}
})
事件参数
<body>
//绑定事件
<div>现在数值为:{{count}}</div>
<button v-on:cilck="addCount(2)">+1</button> //点击后count自增2
</body>
const vm =new vue({
el:'#app',
data:{
count:0
},
methods:{
//事件处理函数
addCount(step){
this.count +=step,
}
}
})
解决参数覆盖事件对象event的问题---$event
<body>
//绑定事件
<div>现在数值为:{{count}}</div>
<button v-on:cilck="addCount(2,$event)">+1</button> //点击后count自增2,背景颜色变为红
</body>
const vm =new vue({
el:'#app',
data:{
count:0
},
methods:{
//事件处理函数
addCount(step,e){
this.count +=step,
e.target.style.backgroundColor='red'
}
}
})
事件修饰符:
.stop:阻止冒泡 用法 给内部盒子添加@click.stop。
.prevent:阻止事件默认行为 用法@click.prevent
.once:事件只触发一次
.self:只有e.target是当前元素时才触发事件
.capture:捕获模式 用法 给外部盒子添加@click.capture。
按键修饰符
.enter
.esc
<body>
<input type='text' @keyup.enter='kenter' @keyup.esc='kesc'>
</body>
const vm =new vue({
el:'#app',
data:{
count:0
},
methods:{
//事件处理函数
//按下回车键,打印input的value值
kenter(e){
console.log(e.target.value)
}
},
kesc(e){
e.target.value=''
}
},
})
4.双向绑定指令
a.v-model 通常在表单元素中使用
v-model = “name”。 name为data中的值
<body>
<input type='text' v-model="name">
</body>
const vm =new vue({
el:'#app',
data:{
name:'zs'
},
})
v-model指令的修饰符
a 、 .lazy (懒加载,表单失去焦点时才发送数据到data)
b 、 .number (转化为数字型)
c、 .trim (除去字符串的前后空格)
5.条件渲染指令
a. v-if 用法:v-if ="name==='小明'",name=小明时显示
b. v-else-if 用法:v-else-if ="name==='小白'",name=小白时显示
c. v -else 用法:v-else ="name==='小花'",name=小花时显示
d. v-show js中的display=now。频繁隐藏时选此。 用法: v-show="flag",flag为true时展示。
6.列表渲染指令
v-for="(item,index) in arr"
<body>
<ul>
<li v-for='(item,index)in arr'> {{item}}</li> //遍历数组
</ul>
</body>
const vm =new vue({
el:'#app',
data:{
arr:['小白','小明','小张']
},
})
使用key维护列表
<body>
<ul>
<li v-for='item in arr' :key=item.id> {{item.name}}</li> //遍历数组
</ul>
</body>
const vm =new vue({
el:'#app',
data:{
arr:[{
name:"小明",
id:1
},
{
name:"小白",
id:2
}]
},
})
7.过滤器
abc | desc: |是管道符
全局过滤器和私有过滤器
//全局过滤器
Vue.filter('desc',(str)=>{return "id是:"+id})
//私有过滤器
<div id='app'> {{ id | desc }}</div>
------------------------------------------
const vm =new Vue({
el:app,
data:{
id:0
},
filter:{
desc(str){
return "id是:"+id
}
}
})
二、SPA(基于vite创建vue工程化项目)
1.使用vite创建工程化项目。
使用vite创建的项目仅适用于vue3。vite不基于webpack。
a.命令 npm init vite-app 项目名称
b.cd 项目名 (执行上一条命令后会提示)
c.npm install(执行上一条命令后会提示)
d.npm run dev(执行上一条命令后会提示)
2.组件的使用
a.组件的三个组成部分
//使用vite创建出来的项目目录中有main.js文件,App.vue文件和index.html文件。通过main.js文件将APP.vue文件中的组件渲染到index.html文件中。vite创建出来的项目属于SPA(单页面应用程序)
<template>
<h1>这是根组件</h1>
<h3>{{stuName}}</h3>
<button @click='addCount'>+1</button>
<p>{{count}}</p>
</template>
<script>
export default{
//使用name指定组件的名称
name:'MyApp',
data(){
return{
stuName:"zh",
count:0
}
}
methods:{
//在这里定义事件处理函数
addCount{
this.count++
}
}
}
</script>
//让文件支持less语法,执行 npm install less -D
<style lang='css'>
button{
background-color='pink'
}
</style>
3.组件的注册
组件之间可以相互引用 父子组件之间,兄弟组件之间。但后来我们会学习vuex。
a.全局注册组件(可在项目目录下任意组件使用)
//在main.js文件中导入需要被全局注册的组件
import TestApp from './Test/testapp.vue'
app.component('test-app',TestApp)
b.局部注册组件(仅在引用组件的当前组件可以使用)
//在需要使用TestAPP组件的 组件内部
<template>
<test-app></test-app>
</template>
<script>
import TestApp from './test/Testapp.vue'
export defaut{
name:"MyApp",
data(){
},
methods:{
function(){}
},
components:{
'test-app':TestApp
}
}
</script>
c.组件之间的样式冲突,因为项目为SPA,所以所有的组件都被渲染成index.html中的dom。
如何解决组件之间的样式冲突:为每个组件分配一个唯一的自定义属性。(太麻烦,需要给每一个元素添加自定义元素),因此,vue为style节点增加了一个scoped属性。
<template>
.....
</template>
<script>
.......
</script>
//在style节点添加scoped属性
<style scoped>
.......
<style>
//但是这里会出现一个问题,那就是当开发者想要在父组件中控制子组件的样式时,无法控制,此时可以采取/deep/样式穿透,vue2:/deep/。vue3: :deep().
--------------------------------------------------------------
<style>
:deep(.container) {
color:red
}
</style>
4.props
a.实现父组件向子组件传递信息
//父组件代码
<template>
<my-son author='余华' book='兄弟'></my-som>
</template>
<script>
import MySon from './test/myson.vue'
export default{
name:'Son',
component:{
Myson
}
}
</script>
--------------------------------------------------------------------------
//子组件代码
<template>
<p>作者:{{author}}</p>
<p>作品:{{book}}</p>
</template>
<script>
export default{
name:'Son',
props:['author','book']
}
</script>
b.动态绑定props的值,使用 v-bind。
//父组件代码
<template>
<my-son :author='person.authore' :book='person.book'></my-som>
</template>
<script>
import MySon from './test/myson.vue'
export default{
name:'Son',
data(){
person:{author:'余华',book:'兄弟'}
},
component:{
Myson
}
}
</script>
--------------------------------------------------------------------------
//子组件代码
<template>
<p>作者:{{author}}</p>
<p>作品:{{book}}</p>
</template>
<script>
export default{
name:'Son',
props:['author','book']
}
</script>
c.给props中的值指定类型:(场景:当props中的值为num时,需要父组件传递一个数值型的字符,但是props列表并不能指定需要接收的值的类型,因此可以使用props对象)
//父组件代码
<template>
<my-son :author='person.authore' :book='person.book'></my-som>
</template>
<script>
import MySon from './test/myson.vue'
export default{
name:'Son',
data(){
person:{author:'余华',book:'兄弟'}
},
component:{
Myson
}
}
</script>
--------------------------------------------------------------------------
//子组件代码
<template>
<p>作者:{{author}}</p>
<p>作品:{{book}}</p>
</template>
<script>
export default{
name:'Son',
props:{
num:Number
}
}
</script>
props属性指定的基础校验类型:字数步(布)数对日韩(函)服(符)。即:字符型(String)、数字型(Number)、布尔型(Boolean)、数组型(Array)、对象型(Object)、日期型(Date)、函数型(Function)、符号型(Symbol)。
d.props同时指定多个类型,通过数组方式。
props:{
name:['String','Number']
}
e.props必填
props:{
name:{
type:Number,
required:true
}
}
f.props属性默认值
props:{
name:{
type:Number,
default:100
}
}
g.props自定义验证
props:{
propD:{
validater(value){
return['小明','小白','小红'].indexOf(value) !==-1
}
}
}
5.class与style动态绑定
class绑定语法:
a. :class=" name ?'name' :' ' "
b. :class='对象名称'
style绑定语法:
a. :style="{color:red,background-color:white}"
6.计算属性computed
computed是属性,并且能够有缓存数据的奇效。
<template>
<p>{{count}}的值为{{plus}}</p>
</template>
<script>
export default{
name:'APP',
data(){
count:1
},
computed:{
plus(){
return this.count * 2
}
}
}
</script>
7.自定义事件
使用this.$emit()
//子组件
<template>
<div>
<p> {{count}}</p>
<button @click ='changeCount'> +1 </button>
</div>
</template>
<script>
export default{
name:'Mytest',
emits:["change"],
data(){
return{
count:0
}
},
methods:{
changeCount(){
this.count++,
//通过 this.$emits 将count值传回父组件。
this.$emits("change",this.count)
}
}
}
</script>
//父组件
<template>
<div>
<p>这是根组件</p>
</div>
<my-test @change ="cchange"></myTest>
</template>
<script>
import MyTest from './test/mytest.vue'
export default{
name:'MyApp',
component:{MyTest},
methods:{
cchange(count){
console.log(count)
}
}
}
</script>
8.组件上的V-model
a.实现父组件向子组件传递数据
//父组件代码
<template>
<my-son :author='person.authore' :book='person.book'></my-som>
</template>
<script>
import MySon from './test/myson.vue'
export default{
name:'Son',
data(){
person:{author:'余华',book:'兄弟'}
},
component:{
Myson
}
}
</script>
--------------------------------------------------------------------------
//子组件代码
<template>
<p>作者:{{author}}</p>
<p>作品:{{book}}</p>
</template>
<script>
export default{
name:'Son',
props:['author','book']
}
</script>
b.子组件向父组件传递数据
//父组件代码
<template>
<my-son v-model:count ='this.number'></my-som>
</template>
<script>
import MySon from './test/myson.vue'
export default{
name:'Son',
data(){
number:0;
},
component:{
Myson
}
}
</script>
--------------------------------------------------------------------------
//子组件代码
<template>
<p>{{count}}</p>
<button @click="addcount"> +1 </button>
</template>
<script>
export default{
name:'Son',
props:['count'],
emits:['update:count'],
methods:{
addcount(){
this.count++,
this.$emit('update:count',this.count)
}
}
}
</script>
9.watch侦听器
//第一种方式
export defaut{
name:"ccc",
data(){
return{
username:"zs"
}
},
watch:{
username(newVal,oldVal){
console.log(newVal+"and"+oldVal)
}
}
}
//第二种方式.当浏览器第一次渲染组件时就开始监听
export defaut{
name:"ccc",
data(){
return{
username:"zs"
}
},
watch:{
username:{
handler(newVal,oldVal){
console.log(newVal+"and"+oldVal)
}
immediate:true,
//可以监听到 对象中的所有值,如果deep值为false,则无法监听对象中的值的变化
deep:true
}
}
}
}
//第二种方式.监听对象中的单个属性
export defaut{
name:"ccc",
data(){
return{
person:{
username:"zs"
}
}
},
watch:{
'person.username':{
handler(newVal,oldVal){
console.log(newVal+"and"+oldVal)
}
immediate:true,
}
}
}
}
计算属性和watch侦听器的区别
计算属性会返回一个值,但watch侦听器不返回值
10.组件的生命周期
组件的生命周期函数会伴随着组建的运行而被调用。
a.常用的组件生命周期函数
我们一般在created 创建组件对象实例阶段发送AjAX请求。
export default{
name:'myTest',
//创建组件的实例对象
created(){
.....
},
//组件第一次加载(渲染)完毕
mounted(){
.....
},
//组件重新渲染完毕
updated(){
....
}
//组件销毁。组件被隐藏时被销毁 v-if
unmounted(){
.....
},
}
b.所有生命周期函数
export default{
name:'myTest',
created(){
.....
},
beforeCreated(){
.....
},
mounted(){
.....
},
beforeMounted(){
.....
},
updated(){
....
},
beforeUpdated(){
....
},
unmounted(){
.....
},
beforeUnmounted(){
.....
}
}
11.兄弟组件之间的数据共享
利用eventbus,可以借助第三方mitt包来创建eventbus对象
安装mitt :npm install mitt
步骤:a.创建eventBus.js文件
import mitt from 'mitt'
const eventbus =mitt()
export default bus
b.代码实现功能
//兄弟组件1 发送方
<script>
import mitt from './test/mitt'
export default{
data(){
return{
count:0
}
},
methods:{
//点击count+1
addCount(){
this.count +=1,
bus.emit('adCount',this.count)
}
}
}
</script>
//兄弟组件2 接收方
<script>
import mitt from './test/mitt'
export default{
data(){
return{
count:0
}
},
created(){
bus.on(adCount,(val)=>{this.count =val})
}
}
</script>
12.vuex的基本使用:实现数据统一管理
步骤:a.安装vuex :npm install vuex --save
b.main.js导入vuex包
import Vuex from 'vuex'
Vue.use(Vuex)
c.创建store对象
d.将store对象挂在到vue实例中
三、插槽
插槽相当于一个占位符,给组件使用者提供插槽使得使用者能够插入一些内容
//封装组件 My-test
<template>
<p> 这是1</p>
<slot name='one'></slot>
<p> 这是2 </p>
<slot name='two'></slot>
<p> 这是3 </p>
<slot ></slot>
</template>
//使用组件,用template包裹,并使用“v-slot:名称”指定插槽名称,可以简写为“#”
<my-test>
<template v-slot:one>
<p>hhh</p>
</template>
<template #two>
<p>hhddh</p>
</template>
<p >bbbbb</p>
</my-test>
三、路由
1.前端路透的工作方式
a.用户点击了页面上的路由链接
b.导致了URL地址栏中的Hash值发生了变化
c.前端路由监听到了Hash地址的变化
d.前端路由把当前Hash地址对应的组件渲染到浏览器中