侦听器
1、什么是 watch 侦听器
watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。
侦听器的格式:
1、方法格式的侦听器
缺点1:无法在刚进入页面的时候,自动触发默认值 缺点2:如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器
2、对象格式的侦听器
好处1:可以通过immediate选项,让侦听器自动触发! 好处2:可以通过deep选项,让侦听器深度监听对象中每个属性的变化! 方法格式的侦听器语法格式如下:
<div id="app">
<input type="text" v-model="username">
</div>
<script src="js/v2.6.10/vue.js"></script>
<script>
const vm = new Vue({
el:'#app',
data:{
username:''
},//所有的侦听器,都应该定义到 watch 节点下
watch:{
//侦听器本质上是一个函数,要监听那个数据的变化,就把数据名作为方法名即可,规定
//第一个形参永远都是:newVal 是"变化后的新值",第二个形参永远都是:oldVal 是"变化之前的值"
//newVal和oldVal名字可以变
username(newVal,oldVal){
console.log("新值:"+newVal+"旧值:"+oldVal);
}
}
})
</script>
2、对象格式的侦听器:
默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使用 immediate 选项。 示例如下:
<div id="app">
请输入用户名:<input type="text" v-model="userName">
</div>
<script src="js/v2.6.10/vue.js"></script>
<script src="js/jquery-3.6.1.js"></script>
<script>
const vm = new Vue({
el:'#app',
data:{
userName:'admin'
},
watch:{
//定义对象格式的侦听器
userName:{
//侦听器的处理函数
//只要监视到了userName值的变化,会自动触发handler函数
handler(newVal,oldVal){
if(newVal === '') return //如果 newVal 等于 null return出去
//1、调用jQuery中的 Ajax 发起请求,判断 newVal 是否被占用
$.get('https://www.escook.cn/api/finduser/'+newVal,result=>{
//把newVal,发送给服务器
console.log(result)
})
},
//immediate里面的true表示一进入页面就会触发handler函数,
//false表示一进页面就不会触发handler函数
//immediate默认值是false
immediate:true
}
}
})
</script>
3、深度侦听:
如果 watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用 deep 选项 示例如下:
<div id="app">
请输入用户名:<input type="text" v-model="info.userName" />
</div>
<script src="js/v2.6.10/vue.js"></script>
<script src="js/jquery-3.6.1.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
//用户的信息对象
info:{
userName:'admin'
}
},
watch:{
//侦听的是 data 里面的 info 对象
info:{
handler(newVal){
console.log(newVal);
},
//开启深度监听,只要对象中任何一个属性发生变化了,都会触发对象侦听器
//deep属性,默认未开启,需要手动开启,true开启,false未开启
deep:true
}
//如果要侦听的是对象的子属性的变化:则必须包裹一层单引号
// 示例:
'info.userName'(newVal,oldVal){
console.log(newVal,oldVal);
}
}
})
</script>
4、jQuery中的Ajax判断用户名是否被占用:
<div id="app">
请输入用户名:<input type="text" v-model="userName">
</div>
<script src="js/v2.6.10/vue.js"></script>
<script src="js/jquery-3.6.1.js"></script>
<script>
const vm = new Vue({
el:'#app',
data:{
userName:''
},
watch:{
userName(newVal){
if(newVal === '') return //如果 newVal 等于 null return出去
//1、调用jQuery中的 Ajax 发起请求,判断 newVal 是否被占用
$.get('https://www.escook.cn/api/finduser/'+newVal,result=>{//把newVal,发送给服务器
console.log(result)
})
}
}
})
</script>
计算属性:
1. 什么是计算属性:
计算属性指的是通过一系列运算之后,最终得到一个属性值。 这个动态计算出来的属性值可以被模板结构或 methods 方法使用。示例代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
*{
margin: 0px;
padding: 0px;
}
#box{
width: 200px;
height: 200px;
background-color: #000000;
}
</style>
</head>
<body>
<div id="app">
R:<input type="text" v-model.number="r"><br>
G:<input type="text" v-model.number="g"><br>
B:<input type="text" v-model.number="b">
<!-- 差值表达式都是js代码 -->
<!-- :style 代表动态绑定一个样式对象 ,它的值是{ }对象 -->
<!-- 当前的样式对象,只包含 backgroundColor 背景颜色 ,里面的值是动态的 -->
<div id="box" :style="{ backgroundColor:`rgb( ${r} , ${g} , ${b} )` }">
{{ `rgb( ${r} , ${g} , ${b} )` }}
</div>
<button @click="showRgb">按钮</button>
<p>computed属性:{{ show }}</p>
</div>
<script src="js/v2.6.10/vue.js"></script>
<script>
const vm = new Vue({
el:'#app',
data:{
//红
r:0,
//绿
g:0,
//蓝
b:0
},
methods:{
showRgb(){
console.log(`rgb( ${this.r} , ${this.g} , ${this.b} )`)
}
},
computed:{
show(){
return `rgb( ${this.r} , ${this.g} , ${this.b} )`
}
}
})
</script>
</body>
</html>
2.计算属性的特点
① 虽然计算属性在声明的时候被定义为方法,但是计算属性的本质是一个属性 ② 计算属性会缓存计算的结果,只有计算属性依赖的数据变化时,才会重新进行运算
特点:
1、定义的时候,要被定义为"方法"
2、在使用计算属性的时候,当普通的属性使用即可
好处:
1、实现了代码的复用
2、只要计算属性中依赖的数据变化了,则计算属性会自动重新求值
axios(Web数据交互方式)
介绍:
axios是一个专注于网络请求的库!
Axios,是一个基于promise 的网络请求库,作用于node.js和浏览器中,它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生node.js 模块, 而在客户端 (浏览端) 则使用XMLHttpRequest。
axios的基本使用
1、使用GET方式发起请求
axios({
method:'GET', //请求方式
url:'http:www.liulongbin.top:3006/api/getbooks',//请求地址
//url(GET) 中的查询参数
params:{
id:1
},
//请求体参数 (POST)
data:{}
}).then(function(result){
console.log(result)
})
2、使用POST方式发起请求
<body>
<button id="btnPost">发起POST请求</button>
<script src="js/axios.js"></script>
<script>
document.querySelector('#btnPost').addEventListener('click',async function(){
//如果调用某个方法的返回值是 Promise 实例,则前面可以添加个 await!
//await 只能用在被 async "修饰"的方法中
const result = await axios({
method:'POST',
url:'http://www.liulongbin.top:3006/api/post',
data:{
name:'zs',
age:20
}
})
// .then(function(result){
// console.log(result)
// })
console.log(result)
})
</script>
</body>
axios使用解构赋值
<body>
<button id="btnPost">发起POST请求</button>
<button id="btnGet">发起GET请求</button>
<script src="js/axios.js"></script>
<script>
document.querySelector('#btnPost').addEventListener('click',async function(){
//如果调用某个方法的返回值是 Promise 实例,则前面可以添加个 await!
// 调用 axios 返回的就是 Prmise 使用 ,则可以使用 await
//await 只能用在被 async "修饰"的方法中
//使用解构赋值,把axios里面的data数据拿过来
const { data } = await axios({
method:'POST',
url:'http://www.liulongbin.top:3006/api/post',
data:{
name:'zs',
age:20
}
})
console.log(data)
})
document.querySelector('#btnGet').addEventListener('click',async function(){
//解构赋值的时候,使用 :进行重命名
//1、调用 axios 之后,使用 async/await 进行简化
//2、使用解构赋值,从axios封装的大对象中 data 属性解构出来
//3、把解构出来的 data 属性,使用冒号进行重命名,一般重命名为 { data : result }
const { data : result } = await axios({
method:'GET',
url:'http://www.liulongbin.top:3006/api/getbooks',
params:{
id:1
}
})
console.log(result.data)
})
</script>
</body>
axios.get 和 axios.post 请求方式
<body>
<button id="btnGet">GET请求</button>
<button id="btnPost">POST请求</button>
<script src="js/axios.js"></script>
<script>
document.querySelector('#btnGet').addEventListener('click',async function(){
// axios.get('url地址',{
// //get参数
// params:{}
// })
const { data : result } =await axios.get('http://www.liulongbin.top:3006/api/getbooks',{
params:{
id:1
}
})
console.log(result)
})
document.querySelector('#btnPost').addEventListener('click',async function(){
// axios.post('url',{
// //这是post请求体数据
// })
const { data : result } = await axios.post('http://www.liulongbin.top:3006/api/post',{
name:'zs',
gender:'女'
})
console.log(result)
})
</script>
</body>
vue-cli
1.什么是单页面应用程序:
单页面应用程序(英文名:Single Page Application)简称 SPA,顾名 思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能 与交互都在这唯一的一个页面内完成。
2.什么是 vue-cli:
vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程。 引用自 vue-cli 官网上的一句话: 程序员可以专注在撰写应用上,而不必花好几天去纠结 webpack 配置的问题。 中文官网:https://cli.vuejs.org/zh/
3.安装和使用:
vue-cli 是 npm 上的一个全局包,使用 npm install 命令,即可方便的把它安装到自己的电脑上: npm install -g @vue/cli 简写 npm i -g @vue/cli -g:全局安装 基于 vue-cli 快速生成工程化的 Vue 项目: vue create 项目的名称 检查 vue-cli 版本号: vue -V
安装 :
1、选择自定义选项,按回车进入下一项
2.选择Babel和cssPre-processors,使用上下箭头调到Babel和cssPre-processors按空格选中,然后按回车进入下一项
3.选择2.0,2.0是vue2.0,然后按回车进入下一项
4.选择Less语法,按回车进入下一项
5.选择In dedicated config files ,让Babel和cssPre-processors放到独立配置文件,In package.json 是把下载的模块放到package.json文件里面,然后等待即可
4.vue 项目的运行流程
在工程化的项目中,vue 要做的事情很单纯:通过 main.js 把 App.vue 渲染到 index.html 的指定区域中。 其中: ① App.vue 用来编写待渲染的模板结构 ② index.html 中需要预留一个 el 区域 ③ main.js 把 App.vue 渲染到了 index.html 所预留的区域中
Vue 组件
1.什么是组件化开发
组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。
2.vue 中的组件化开发
vue 是一个支持组件化开发的前端框架。 vue 中规定:组件的后缀名是 .vue。之前接触到的 App.vue 文件本质上就是一个 vue 的组件。
3.vue 组件的三个组成部分
每个 .vue 组件都由 3 部分构成,分别是:
template -> 组件的模板结构 script -> 组件的 JavaScript 行为 style -> 组件的样式
其中,每个组件中必须包含 template 模板结构,而 script 行为和 style 样式是可选的组成部分。
3.1 template
vue 规定:每个组件对应的模板结构,需要定义到 template 标签节点中。
注意: template 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素 template 中只能包含唯一的根节点
3.2 script
vue 规定:开发者可以在 script标签 节点中封装组件的 JavaScript 业务逻辑。 script 标签 节点的基本结构如下:
<script>
// 今后,组件相关的 data 数据,methods 方法等...
// 都需要定义到 export default 所导出的对象中,
export default{}
</script>
.vue 组件中的 data 必须是函数: vue 规定:.vue 组件中的 data 必须是一个函数,不能直接指向一个数据对象。 因此在组件中定义 data 数据节点时,下面的方式是错误的: data:{ // 组件中,不能直接让 data 指向一个数据对象 (会报错) count:0 }
会导致多个组件实例共用同一份数据的问题,请参考官方给出的示例:
https://cn.vuejs.org/v2/guide/components.html#data-必须是一个函数
3.3 style
vue 规定:组件内的 style 标签节点是可选的,开发者可以在 style标签节点中编写样式美化当前组件的 UI 结构。 script标签节点的基本结构如下:
<style>
h1{
font-weight: normal;
}
</style>
让 style 中支持 less 语法: 在 style 标签上添加 lang="less" 属性,即可使用 less 语法编写组件的样式:
<style lang="less">
h1{
font-weight: normal;
}
</style>
4.组件之间的父子关系
组件在被封装好之后,彼此之间是相互独立的,不存在父子关系 在使用组件的时候,根据彼此的嵌套关系,形成了父子关系、兄弟关系
4.1 使用组件的三个步骤
步骤1:使用 import 语法导入需要的组件:
import Right from '@/components/Right.vue'
步骤2:使用 components 节点注册组件
export default {
components: {
Right
}
}
步骤3:以标签形式使用刚才注册的组件
<div class="box">
<Right></Right>
</div>
4.2 通过 components 注册的是私有子组件
例如:
在组件 A 的 components 节点下,注册了组件 F。 则组件 F 只能用在组件 A 中;不能被用在组件 C 中。
4.3 注册全局组件
在 vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。
示例代码如下:
//导入需要注册的全局组件
import Right from '@/components/Right.vue'
//参数1:字符串格式,表示组件的"注册名称"
//参数2:需要被全局注册的那个组件
Vue.component('Right',Right)
5.组件的 props
props 是组件的自定义属性,在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性! 它的语法格式如下:
export default {
//组件的自定义属性
props:['init'],
//组件的私有数据
data(){
return{}
}
}
5.1 props 是只读的
vue 规定:组件中封装的自定义属性是只读的,程序员不能直接修改 props 的值。否则会直接报错
要想修改 props 的值,可以把 props 的值转存到 data 中,因为 data 中的数据都是可读可写的!
export default{
props:['init'],
data() {
return{
count: this.init
}
}
}
5.2 props 的 default 默认值
在声明自定义属性时,可以通过 default 来定义属性的默认值。示例代码如下:
export default{
props:{
init:{
//如果外界使用 Coun 组件的时候,没有传递 init属性,则默认值生效
default:0
}
}
}
5.3 props 的 type 值类型
在声明自定义属性时,可以通过 type 来定义属性的值类型。
示例代码如下:
export default{
props:{
init:{
//如果外界使用 Coun 组件的时候,没有传递 init属性,则默认值生效
default:0,
//init的值传递的不是 Number 类型的值,则终端报错
type:Number
}
}
}
5.4 props 的 required 必填项
在声明自定义属性时,可以通过 required 选项,将属性设置为必填项,强制用户必须传递属性的值。
示例代 码如下:
export default{
props:{
init:{
//如果外界使用 Coun 组件的时候,没有传递 init属性,则默认值生效
default:0,
//init的值传递的不是 Number 类型的值,则终端报错
type:Number,
//必填项校验,如果不填 init 的值则终端报错,如果有默认值的话,也会报错
require:true
}
}
}
6.组件之间的样式冲突问题
默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。 导致组件之间样式冲突的根本原因是: ① 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的 ② 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素
6.1 思考:如何解决组件样式冲突的问题
为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器来控制样式的作用域。
示例代码如下:
<template>
<div class="left-container">
<h3 data-v-001>Left 组件</h3>
</div>
</template>
<script>
export default{}
</script>
<style lang="less">
.left-container{
padding: 0 20px 20px;
background-color: lightskyblue;
min-height: 250px;
flex: 1;
}
h3[data-v-001]{
color: red;
}
</style>
6.2 style 节点的 scoped 属性
为了提高开发效率和开发体验,vue 为 style 节点提供了 scoped 属性,从而防止组件之间的样式冲突问题:
<template>
<div class="left-container">
<h3>Left 组件</h3>
</div>
</template>
<script>
export default{}
</script>
<style lang="less" scoped>
.left-container{
padding: 0 20px 20px;
background-color: lightskyblue;
min-height: 250px;
flex: 1;
}
h3{
color: red;
}
</style>
6.3 /deep/ 样式穿透
如果给当前组件的 style 节点添加了 scoped 属性,则当前组件的样式对其子组件是不生效的。如果想让某些样 式对子组件生效,可以使用 /deep/ 深度选择器
示例如下:
<template>
<div class="left-container">
<h3>Left 组件</h3>
<count :init="1"></count>
</div>
</template>
<script>
export default{}
</script>
<style lang="less" scoped>
.left-container{
padding: 0 20px 20px;
background-color: lightskyblue;
min-height: 250px;
flex: 1;
}
// 不加 /deep/: h5 [data-v-3c83f0b7]
//加 /deep/ : [data-v-3c83f0b7] h5
// /deep/ :会先找父元素的 data-v-3c83f0b7 然后再找标签
//当使用第三方组件库的时候,如果有修改第三方默认样式的需求,需要用到 /deep/
/deep/ h5{
color: pink;
}
</style>
组件的生命周期
1.生命周期 & 生命周期函数
生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段。
生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行。
注意:生命周期强调的是时间段,生命周期函数强调的是时间点。
2. 组件生命周期函数的分类
3.生命周期图示
生命周期分为三个阶段:
1.创建阶段:一个.vue文件只执行一次
1.beforeCreate
创建阶段的 props/data/methods 尚未被创建,都处于不可用的状态
beforeCreate() {
console.log("初始化事件和生命周期")
}
2.created
created 生命周期函数,非常常用
经常在它里面,调用 methods 中的方法,请求服务器的数据
并且,把请求到的数据,转存到 data 中,供 template 模板渲染的时候使用!
created(){
console.log("组件创建好阶段")
console.log(this.info)
console.log(this.message)
this.show()
console.log("ajax请求:")
this.initBookList()
console.log("----------------")
}
3.beforeMount
将要把内存中编译好的 HTML 结构渲染到浏览器中,此时浏览器中还没有当前组件的 DOM 结构
beforeMount(){
console.log("beforeMount")
}
注意: beforeMount 操作不了 dom 元素
4.mounted
已经把内存中的 HTML 结构,成功的渲染到浏览器之中,此时浏览器已经包含了当前组件的 DOM 结构
如果要操作当前组件的 DOM 最早,只能在 mounted 阶段执行
mounted() {
console.log("mounted")
}
2.运行阶段:运行阶段函数最少执行0次,如果数据没发生变化就不会执行,最多执行 N 次
1.beforeUpdate:
将要根据变化过后、最新的数据,重新渲染组件的模板结构
beforeUpdate(){
console.log("beforeUpdate")
}
2.updated
根据最新的数据,重新渲染组件的 DOM 结构
当数据变化之后,为了能够操作到最新的 DOM 结构,必须把代码写到 updated 生命周期函数中
updated(){
console.log("updated")
}
3.销毁阶段:一个.vue文件只执行一次
1.beforeDestroy
将要销毁此组件,此时尚未销毁,组件还处于正常工作的状态
beforeDestroy(){
console.log("组件销毁之前")
console.log(this.message)
}
2.destroyed
组件已经被销毁,此组件在浏览器中对应 DOM 结构已被完全移除
destroyed(){
console.log("组件销毁了")
}
组件之间的数据共享
1. 组件之间的关系
在项目开发中,组件之间的最常见的关系分为如下两种:
① 父子关系
② 兄弟关系
2. 父子组件之间的数据共享
父子组件之间的数据共享又分为:
① 父 -> 子共享数据
② 子 -> 父共享数据
2.1 父组件向子组件共享数据
父组件向子组件共享数据需要使用自定义属性。示例代码如下:
2.2 子组件向父组件共享数据
子组件向父组件共享数据使用自定义事件。示例代码如下:
3.兄弟组件之间的数据共享
在 vue2.x 中,兄弟组件之间数据共享的方案是 EventBus。
EventBus 的使用步骤
① 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象
② 在数据发送方,调用 bus.$emit('事件名称', 要发送的数据) 方法触发自定义事件
③ 在数据接收方,调用 bus.$on('事件名称', 事件处理函数) 方法注册一个自定义事件