侦听器

什么是watch侦听器

允许开发者监视数据的变化,从而针对数据的变化做特定的操作。

  • 数据值发生变化,就会自动触发侦听器。
  • 所有侦听器都被定义到watch节点下。
  • 侦听器本质是个函数,要监视哪个数据的变化,就把数据名作为方法名即可。
  • 侦听器的参数是新值在前,旧值在后。
  • 典型应用场景:判断用户名是否被占用。

侦听器的格式

方法格式的侦听器(先考虑)

  • 缺点1:无法在刚进入页面的时候立即触发。
  • 缺点2:如果真听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器。
    • 如果要侦听的是对象子属性的变化,可以使用该方法,但是注意:必须包裹一层单引号。

对象格式的侦听器

  • 好处1:可以通过immediate选项,让侦听器自动触发。
    • immediate作用:控制侦听器是否自动触发一次。
    • 默认值是false,true表示一进入页面就会触发一次侦听器。
  • 好处2:可以通过deep选项,让侦听器深度侦听对象中每个属性的变化。
    • deep作用:只要对象中任何一个属性变化了,都会触发“对象的侦听器”。
    • 默认值是false。
javascript
//方法格式的侦听器
const vm = new Vue({
el:'#app',
data:{username:''},
watch:{
//newVal:变化后的新值,oldVal:变化前的旧值
//监听username值的变化
username(newVal,oldVal) {
console.log(newVal,oldVal);
}
}
})

//对象格式的侦听器
//(immediate)
watch: {
username:{
//侦听器的处理函数(只要监视到username值的变化,就会触发该函数)
handler(newVal,oldVal) {
console.log(newVal,oldVal);
},
//immediate选项的默认值是false,true表示一进入页面就会触发一次侦听器。
//作用:控制侦听器是否自动触发一次。
immediate:true
}
}

//(deep)
<input type="text" v-model="info.username"/>
data:{
info:{
username:'admin'
}
},
watch:{
info:{
handler(newVal) {
console.log(newVal.username);
},
//开启深度监听,只要对象中任何一个属性变化了,都会触发“对象的侦听器”
deep:true,
}
}
//如果只监听username,也可以用如下代码
watch:{
'info.username' (newVal) {
console.log(newVal); //得到的就是info对象里的username值
}
}
//或:
watch:{
'info.username':{
handler(newVal) {
console.log(newVal);
}
}
}

计算属性

计算属性指通过一系列运算后,最终得到一个属性值,这个动态计算出来的属性值可以被模板结构或methods方法使用。

特点

  • 定义的时候,要被定义成“方法”
  • 使用的时候,当普通属性使用即可。
  • 被定义到computed节点下。

好处

  • 实现了代码的复用。
  • 当计算属性所依赖的数据源发生变化,计算属性会自动重新求值。
javascript
<p>{{rgb}}</p>
computed:{
rgb(){
return `rgb{$(this.r),$(this.g),$(this.b)}`;
}
}

axios

axios是一个专注于数据请求的库。

基础语法

调用axios方法得到的返回值result是个Promise对象【axios在请求到数据之后,在真正的数据之外套了一层壳】。

plaintext
{
config:{},
data:{真实的数据},
header:{},
request:{},
status:xxx,
statusText:''
}

常用格式

  • 调用axios之后,使用 async/await 进行简化。
    • 如果调用某个方法的返回值是Promise实例,则前面可以添加await
    • await只能用在被 async “修饰”的方法中
  • 使用解构赋值,从axios封装的大对象中,把data属性解构出来。
  • 把解构出来的data属性,使用 冒号 进行重命名,一般都重命名为 { data: res }

语法

javascript
//语法如下:
axios({
method:'请求的类型',
url:'请求的URL地址',
params:{URL中的查询参数}, //GET传参
data:{请求体参数} //POST传参
}).then(result) => {
// .then用来指定成功之后的回调函数
}

例子

javascript
//例:
//发起GET请求
axios({
methos:'GET',
url:'http://www.liulongbin.top:3306/api/getbooks',
params:{id:1}
}).then(function(result) {
console.log(result.data);
})

//发起POST请求
axios({
methosd:'POST',
url:'http://www.liulongbin.top:3306/api/getbooks',
data:{
name:'zs',
age:20
}
}).then(function(result) {
console.log(result.data);
})

优化

javascript
//优化:!!!!!
//规则:如果调用某个方法的返回值是Promise实例,则前面可以添加await
//await只能用在被 async “修饰”的方法中
async function() {
//解构赋值的时候,使用 : 进行重命名
const { data:res } = await axios({ //解构赋值
methosd:'POST',
url:'http://www.liulongbin.top:3306/api/getbooks',
data:{
name:'zs',
age:20
}
})
}
console.log(res.data);

axios直接发起GET和POST请求

请求数据发GET,传输数据发POST

Get请求

javascript
axios.get('url地址' [,{
params:{GET参数}
}] )
//例:
async function() {
const { data:res } = await axios.get('http://www.liulongbin.top:3306/api/getbooks',{
params:{
id:1
}
})
}
console.log(res);

Post请求

javascript
axios.post('url地址' [,{ POST请求体数据 }] )
//例:
async function() {
const { data:res } = await axios.post(''http://www.liulongbin.top:3306/api/getbooks'',{
name:'zs',
gender:'女',
},headers:{'Authorization':'本机token'})
}
console.log(res);

vue-cli

单页面应用程序(SPA)

一个web网站中只有唯一的一个HTML页面,所有的功能与交互都在这唯一的一个页面内完成。

什么是vue-cli

vue-cli是Vue.js开发的标准工具,它简化了程序员基于webpack创建工程化的Vue项目的过程。因此,程序员可以专注在撰写应用上,而不必纠结webpack配置的问题。
网址:介绍 | Vue CLI (vuejs.org)

安装和使用

  • vue-cli是npm上的全局包,在终端上输入 npm install -g @vue/cli 就可以安装成功了。
    • 使用 vue–V 指令可以判断是否安装成功
  • vue-cli的使用:
    • 在终端下运行如下命令,创建指定名称的项目: vue create 项目名
      e14baa3852e342578e631a74d8453c6b.png
      7175be17ef9b470fae6adf67ef2ca418.png
      587c36e7a7a94f7fafd78ee209517a5c.png
      ac3239327e20486c9ac0729d48d6346c.png
      fd489e1b7129498c9fc14cc22533b39f.png
      2592a4676d9c437c8cbaa806d92de3b0.png

vue项目中src目录的构成

4bdf91a9d1cd41eba7d3ed858a68fd65.png

  • assets文件夹: 存放项目中用到的静态资源文件。(css样式表、图片资源)
  • components文件夹:程序员封装的、可复用的组件,都要放在components目录下。
  • main.js:是项目的入口文件,整个项目的运行,要先执行main.js。
  • APP.vue:是项目的根组件。

vue项目的运行流程

在工程化的项目中,vue通过 main.js 把 App.vue 渲染到 index.html 的指定区域中。
aaded890e40f4fe9b688c0a250beac3b.png

  • App.vue 用来编写待渲染的模板结构 (render函数中,渲染的是哪个.vue组件,这个组件就叫做根组件)
  • index.html中需要预留一个el区域
  • main.js把App.vue渲染到index.html所预留的区域中

vue组件

什么是组件化开发

根据封装的思想,把页面上可复用的UI结构封装为组件。

vue项目中的组件化开发

  1. vue是个支持组件化开发的前端框架
  2. vue规定:组建的后缀名是.vue

组件的三个组成部分

template:组件的模板结构(要复用的UI结构)

  1. 组件的模板元素中,只能有一个根节点!
  2. 一般根节点的类名就是xxx-container(xxx为组件名)
javascript
<template>
<div class="pink">{{username}}</div>
<button @click="changeName">修改用户名</button>
</template>

script: 组件的JavaScript行为

  1. 使用export default默认导出
  2. 组件中的data必须是个函数 data() { return { 定义数据 } }
  3. 在组件中,this表示当前组件的实例对象
javascript
<script>
//默认导出!固定写法!
export default {
//注意!! .vue中的data,不能像之前一样,不能指向对象。
//组件中的data数据源必须是个函数
data() {
//这个return 出去的{ }可以定义数据。
return {
username:'lsh'
}
},
methods:{
changeName() {
this.username="33"
}
},
//当前组件中的计算属性、侦听器、过滤器
computed:{},
watch:{},
filters:{}
}
</script>

style:组件的样式

javascript
//style中启动less语法
<style lang="less">
.pink {
color:pink;
h3 {
color:red;
}
}
</style>

组件之间的父子关系

23de26cfde744602ad2c63820c0777c2.png

使用组件的三个步骤

  1. 使用import语法导入需要的组件。(在script里面导入)
javascript
import Left from '@/components/Left.vue'
  1. 使用components结点注册组件
javascript
export default {
components:{
Left
}
}
  1. 以标签形式使用刚才注册的组件
javascript
<div>
<Left></Left>
</div>

通过components注册的是私有子组件
缺点:如果某个组件使用频率高,会很麻烦

注册全局组件:在vue项目的main.js入口文件中,通过Vue.components()方法,可以注册全局组件。
import Count from ‘@/components/Count.vue’
Vue.component(‘Count’,Count);

组件的props

props是组件的自定义属性,在封装通用组件的时候,合理地使用props可以极大地提高组件的复用性。

v-bind(父传子,加了准没错!)

  • 当传递的是个数字,而不是data里的数据时:
    • 不使用v-bind传递的是字符串。
    • 使用v-bind传递的是数字。
  • 当传递的是个data里面的数据时:
    • 不使用v-bind传递的是该数据的变量名。
    • 使用v-bind传递的是该数据的属性值。

props中的数据

  • props中的数据,可以直接在模板结构中被使用
  • props中的数据是只读的,程序员不能修改props的值,否则终端会报错。
    • 想要修改props的值,可以把props的值转存到data中,因为data中的数据都是可读可写的。

default设置默认值

  • 把props改成对象形式,里面通过default指定默认值。
  • 外界如果没有传递属性,则默认值生效
  • 如果要给对象设置默认值:
    86269b196606447a9dc81b98e62d7831.png

type定义属性的值

  • 在声明自定义属性时,可以通过type来定义属性的值类型
  • 如果传递过来的值不符合此类型,则会在终端报错
  • Number、Boolean、String、Array、Object…
  • 可以通过数组形式,为当前属性定义多个可能的类型。type: [Number, String]

require必填项

  • 某个属性如果设置required的值为true,则必须要传递改属性。
  • required只关心是否传值,不关心传递类型是否符合。
javascript
export default {
//组件的自定义属性
props:['自定义属性A','自定义属性B','其他自定义属性...'],
//或
props:{
//外界使用该组件,没有传这些属性,则默认值生效
自定义属性A:{
default:默认值1,
type:Number, //规定传值类型
required:true //必填项校验
},
自定义属性B:{defalt:默认值2},
自定义属性C:{defalt:默认值3},
}
//组件的私有数据
data() {
return { }
}
}

//例:
//Count.vue文件
<template>
<div>Count的值:{{count}}</div>
</template>
export default {
props:['init'],//这样如果别的组件想要给Count传值的话,可以通过init来传
//或
props:{
init:{
//用default属性定义属性的默认值
default:0,
type:Number,
required:true
}
}
data(){
return {
count:this.init
}
}
}

//App.vue文件
<template>
//不使用v-bind 传递的是字符串
<Count init="6"></Count>
//使用v-bind 传递的是数字
<Count :init="6"></Count>
</template>

组件之间的样式冲突

默认情况下,写在.vue里的组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

原因:

  • 单页面应用程序中,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的。
  • 每个组件的样式,都会影响整个index.html页面的DOM元素。

解决:

  • 给当前组件的style添加 scoped 属性。
  • 当使用给第三方组件库的时候,如果有修改组件默认样式的需求,需要用到**/deep/**
javascript
<style lang="less" scoped></style>

【补】:浏览器无法正常解析.vue结尾的文件
“vue-template-compiler”: “^2.6.11”:vue模板编译器(帮助程序员将.vue结尾的文件编译成js,再交给浏览器去解析)

【关于自定义属性的传值问题】:一般来说,传值不要传对象,传的是对象里的每个属性。这样可复用性强。