vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件

文章目录

  • 1.侦听器
    • 1.1. 什么是 watch 侦听器
    • 1.2. 使用 watch 检测用户名是否可用
    • 1.3 侦听器的格式
      • 1.3.1 方法格式的侦听器
      • 1.3.2 对象格式的侦听器
    • 1.4.格式 immediate 选项(布尔类型)
    • 1.5. deep 选项 (布尔型)
    • 1.6. 监听对象单个属性的变化
  • 2. 计算属性(computed)
    • 2.1. 什么是计算属性
    • 2.2. 计算属性的特点
    • 2.3 axios (网址)
    • 2.4 axios 的基本使用
      • 2.4.1 使用axios发起基本的 get 请求
      • 2.4.2 使用axios发起基本的 post 请求
      • 2.4.3 使用解构赋值
      • 2.4.4 基于axios.get和axios.post发起请求
  • 3. vue-cli
    • 3.1. 什么是单页面应用程序
    • 3.2. 什么是 vue-cli
    • 3.3. 安装和使用
      • 3.3.1 vue 项目中 src 目录的构成
    • 3.4. vue 项目的运行流程
      • index .html
      • app.vue
      • main.js
  • 4. vue 组件
    • 4.1. 什么是组件化开发
    • 4.2. vue 中的组件化开发
    • 4.3. vue 组件的三个组成部分
      • 4.3.1 template
      • 4.3.2 script
      • 4.3.3 style
  • 4. 组件之间的父子关系
    • 4.1 使用组件的三个步骤
    • 4.2 通过 components 注册的是私有子组件
    • 4.3 注册`全局组件`
  • 5. 组件的 props
    • 5.1 props 是只读的
    • 5.2 props 的 `default` 默认值
    • 5.3 props 的 `type` 值类型
    • 5.4 props 的 `required` 必填项
  • 6. 组件之间的样式冲突问题
    • 6.1 思考:如何解决组件样式冲突的问题
    • 6.2 style 节点的 scoped 属性
    • 6.3 `/deep/` 样式穿透

1.侦听器

1.1. 什么是 watch 侦听器

watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。
语法格式如下:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <input type="text" v-model="username">

    div>
    <script src="./lib/vue-2.6.12.js">script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                username: 'ggg'
            },
            watch: {
                username(newVal, oldVal) {
                    console.log('监听到了username值的变化', newVal, oldVal)
                }
            }


        })
    script>
body>

html>

vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第1张图片

1.2. 使用 watch 检测用户名是否可用

监听 username 值的变化,并使用 axios 发起 Ajax 请求,检测当前输入的用户名是否可用:

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>

<body>
  <div id="app">
    <input type="text" v-model="username">
  div>

  <script src="./lib/vue-2.6.12.js">script>
  <script src="./lib/jquery-v3.6.0.js">script>

  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        username: 'admin'
      },
      // 所有的侦听器,都应该被定义到 watch 节点下
      watch: {
        // 侦听器本质上是一个函数,要监视哪个数据的变化,就把数据名作为方法名即可
        // 新值在前,旧值在后
        username(newVal) {
          if (newVal === '') return
          // 1. 调用 jQuery 中的 Ajax 发起请求,判断 newVal 是否被占用!!!
          $.get('https://www.escook.cn/api/finduser/' + newVal, function (result) {
            console.log(result)
          })
        }
      }
    })
  script>
body>

html>

1.3 侦听器的格式

1.3.1 方法格式的侦听器

  • 缺点1:无法在刚进入页面的时候,自动触发!!!
  • 缺点2:如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器!!!

1.3.2 对象格式的侦听器

  • 好处1:可以通过 immediate 选项,让侦听器自动触发!!!
  • 好处2:可以通过 deep 选项,让侦听器深度监听对象中每个属性的变化!!!

1.4.格式 immediate 选项(布尔类型)

默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使用 immediate 选项。示例代码如下:

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>

<body>
  <div id="app">
    <input type="text" v-model="username">
  div>

  <script src="./lib/vue-2.6.12.js">script>
  <script src="./lib/jquery-v3.6.0.js">script>

  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        username: 'admin'
      },
      // 所有的侦听器,都应该被定义到 watch 节点下
      watch: {
        // 定义对象格式的侦听器
        username: {
          // 侦听器的处理函数
          handler(newVal, oldVal) {
            console.log(newVal, oldVal)
          },
          // immediate 选项的默认值是 false
          // immediate 的作用是:控制侦听器是否自动触发一次!
          immediate: true
        }
      }
    })
  script>
body>

html>

1.5. deep 选项 (布尔型)

如果 watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用 deep 选 项,代码示例如下:

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>

<body>
  <div id="app">
    <input type="text" v-model="info.username">
    <input type="text" v-model="info.address.city">
  div>

  <script src="./lib/vue-2.6.12.js">script>
  <script src="./lib/jquery-v3.6.0.js">script>

  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        // 用户的信息对象
        info: {
          username: 'admin',
          address: {
            city: '北京'
          }
        }
      },
      // 所有的侦听器,都应该被定义到 watch 节点下
      watch: {
         info: {
          handler(newVal) {
            console.log(newVal)
          },
          // 开启深度监听,只要对象中任何一个属性变化了,都会触发“对象的侦听器”
          deep: true
        } 
      }
    })
  script>
body>

html>

1.6. 监听对象单个属性的变化

如果只想监听对象中单个属性的变化,则可以按照如下的方式定义 watch 侦听器:

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>

<body>
  <div id="app">
    <input type="text" v-model="info.username">
    <input type="text" v-model="info.address.city">
  div>

  <script src="./lib/vue-2.6.12.js">script>
  <script src="./lib/jquery-v3.6.0.js">script>

  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        // 用户的信息对象
        info: {
          username: 'admin',
          address: {
            city: '北京'
          }
        }
      },
      // 所有的侦听器,都应该被定义到 watch 节点下
      watch: {
        // 如果要侦听的是对象的子属性的变化,则必须包裹一层单引号
        'info.username'(newVal) {
          console.log(newVal)
        }
      }
    })
  script>
body>

html>

2. 计算属性(computed)

2.1. 什么是计算属性

计算属性指的是通过一系列运算之后,最终得到一个属性值。
这个动态计算出来的属性值可以被模板结构或 methods 方法`使用。示例代码如下:
未使用计算属性的代码:

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Documenttitle>
  <script src="./lib/vue-2.6.12.js">script>
  <style>
    .box {
      width: 200px;
      height: 200px;
      border: 1px solid #ccc;
    }
  style>
head>

<body>
  <div id="app">
    <div>
      <span>R:span>
      <input type="text" v-model.number="r">
    div>
    <div>
      <span>G:span>
      <input type="text" v-model.number="g">
    div>
    <div>
      <span>B:span>
      <input type="text" v-model.number="b">
    div>
    <hr>

    
    
    
    
    <div class="box" :style="{ backgroundColor: `rgb(${r}, ${g}, ${b})` }">
      {{ `rgb(${r}, ${g}, ${b})` }}
    div>
    <button @click="show">按钮button>
  div>

  <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        // 红色
        r: 0,
        // 绿色
        g: 0,
        // 蓝色
        b: 0
      },
      methods: {
        // 点击按钮,在终端显示最新的颜色
        show() {
          console.log(`rgb(${this.r}, ${this.g}, ${this.b})`)
        }
      },
    });
  script>
body>

html>

结果如下:
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第2张图片
用过计算属性改造过的案例(实现了代码的复用):

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Documenttitle>
  <script src="./lib/vue-2.6.12.js">script>
  <style>
    .box {
      width: 200px;
      height: 200px;
      border: 1px solid #ccc;
    }
  style>
head>

<body>
  <div id="app">
    <div>
      <span>R:span>
      <input type="text" v-model.number="r">
    div>
    <div>
      <span>G:span>
      <input type="text" v-model.number="g">
    div>
    <div>
      <span>B:span>
      <input type="text" v-model.number="b">
    div>
    <hr>

    
    
    
    
    <div class="box" :style="{ backgroundColor: rgb }">
      {{ rgb }}
    div>
    <button @click="show">按钮button>
  div>

  <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        // 红色
        r: 0,
        // 绿色
        g: 0,
        // 蓝色
        b: 0
      },
      methods: {
        // 点击按钮,在终端显示最新的颜色
        show() {
          console.log(this.rgb)
        }
      },
      // 所有的计算属性,都要定义到 computed 节点之下
      // 计算属性在定义的时候,要定义成“方法格式”
      computed: {
        // rgb 作为一个计算属性,被定义成了方法格式,
        // 最终,在这个方法中,要返回一个生成好的 rgb(x,x,x) 的字符串
        rgb() {
          return `rgb(${this.r}, ${this.g}, ${this.b})`
        }
      }
    });

    console.log(vm)
  script>
body>

html>

2.2. 计算属性的特点

① 虽然计算属性在声明的时候被定义为方法,但是计算属性的本质是一个属性
② 计算属性会缓存计算的结果,只有计算属性依赖的数据变化时,才会重新进行运算

2.3 axios (网址)

axios (发音:艾克c奥斯)是一个专注于网络请求的库!
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第3张图片
中文官网地址:http://www.axios-js.com/
英文官网地址:https://www.npmjs.com/package/axios

2.4 axios 的基本使用

vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第4张图片

2.4.1 使用axios发起基本的 get 请求

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>

    <script src="./lib/axios.js">script>
    <script>
        // http://www.liulongbin.top:3006/api/getbooks

        // 1. 调用 axios 方法得到的返回值是 Promise 对象
        const result = axios({
            // 请求方式
            method: 'GET',
            // 请求的地址
            url: 'http://www.liulongbin.top:3006/api/getbooks',
            
        })
        result.then(function (books) {
            console.log(books.data)
        })
    script>
body>

html>

vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第5张图片

2.4.2 使用axios发起基本的 post 请求

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <button id="btnPost">发起POST请求button>

    <script src="./lib/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
                }
            })

            console.log(result)
        })


    script>
body>

html>

vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第6张图片

2.4.3 使用解构赋值

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>

<body>

  <button id="btnPost">发起POST请求button>
  <button id="btnGet">发起GET请求button>

  <script src="./lib/axios.js">script>
  <script>
    document.querySelector('#btnPost').addEventListener('click', async function () {
      // 如果调用某个方法的返回值是 Promise 实例,则前面可以添加 await!
      // await 只能用在被 async “修饰”的方法中
      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: res }
      const { data: res } = await axios({
        method: 'GET',
        url: 'http://www.liulongbin.top:3006/api/getbooks'
      })

      console.log(res.data)
    })

    // $.ajax()   $.get()  $.post()
    // axios()    axios.get()    axios.post()    axios.delete()   axios.put()
  script>
body>

html>

2.4.4 基于axios.get和axios.post发起请求

DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documenttitle>
head>

<body>
  <button id="btnGET">GETbutton>
  <button id="btnPOST">POSTbutton>

  <script src="./lib/axios.js">script>
  <script>
    document.querySelector('#btnGET').addEventListener('click', async function () {
      /* axios.get('url地址', {
        // GET 参数
        params: {}
      }) */

      const { data: res } = await axios.get('http://www.liulongbin.top:3006/api/getbooks', {
        params: { id: 1 }
      })
      console.log(res)
    })

    document.querySelector('#btnPOST').addEventListener('click', async function () {
      // axios.post('url', { /* POST 请求体数据 */ })
      const { data: res } = await axios.post('http://www.liulongbin.top:3006/api/post', { name: 'zs', gender: '女' })
      console.log(res)
    })
  script>
body>

html>

3. vue-cli

3.1. 什么是单页面应用程序

单页面应用程序(英文名:Single Page Application)简称 SPA,顾名思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。
例如资料中的这个 Demo 项目:
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第7张图片
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第8张图片

3.2. 什么是 vue-cli

vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程。
引用自 vue-cli 官网上的一句话:
程序员可以专注在撰写应用上,而不必花好几天去纠结 webpack 配置的问题。
中文官网:https://cli.vuejs.org/zh/

3.3. 安装和使用

vue-cli 是 npm 上的一个全局包,使用 npm install 命令,即可方便的把它安装到自己的电脑上:npm install -g @vue/cli

出现的问题:npm安装时卡在sill idealTree buildDeps,npm安装速度慢,npm安装卡在一个地方不动
解决的链接:http://t.csdn.cn/wK740
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第9张图片

基于 vue-cli 快速生成工程化的 Vue 项目:vue create 项目的名称

项目的名称最好使用英文
建立vue项目之前:
① 先确定要建立项目的目录(文件的存储位置),
② 打开当前文件夹,在目录里面直接输入cmd
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第10张图片
vue create 项目的名称vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第11张图片
按enter键,选择项目的样式,初学者选择第三项
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第12张图片
让程序员自己选择安装的功能
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第13张图片
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第14张图片
按enter
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第15张图片
按 entervue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第16张图片

vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第17张图片
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第18张图片

复制本机地址,http://localhost:8080/到百度打开,即创建了一个vue项目(终端窗口不要关)
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第19张图片

3.3.1 vue 项目中 src 目录的构成

assets 文件夹:存放项目中用到的静态资源文件,例如:css 样式表、图片资源
components 文件夹:程序员封装的、可复用的组件,都要放到 components 目录下
main.js 是`项目的入口文件`。整个项目的运行,要先执行 main.js
App.vue 是项目的根组件,定义ui结构

3.4. vue 项目的运行流程

在工程化的项目中,vue 要做的事情很单纯:通过 main.jsApp.vue 渲染到 index.html 的指定区域中。

其中:
App.vue 用来编写待渲染的模板结构
index.html 中需要预留一个 el 区域
main.js 把 App.vue 渲染到了 index.html 所预留的区域中
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第20张图片
vue2第三节:侦听器,计算属性(computed),vue-cli和vue 组件_第21张图片

index .html

DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <title>
    <%= htmlWebpackPlugin.options.title %>
  title>
head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.strong>
  noscript>
  <div id="app">div>
  
body>

html>

app.vue



main.js

// 导入 vue 这个包,得到 Vue 构造函数
import Vue from 'vue'
// 导入 App.vue 根组件,将来要把 App.vue 中的模板结构,渲染到 HTML 页面中
// import App from './App.vue'
import Test from './Test.vue'

Vue.config.productionTip = false

// 创建 Vue 的实例对象
new Vue({
  // 把 render 函数指定的组件,渲染到 HTML 页面中
  render: h => h(Test)
}).$mount('#app')

// Vue 实例的 $mount() 方法,作用和 el 属性完全一样!

4. vue 组件

4.1. 什么是组件化开发

组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。

4.2. vue 中的组件化开发

vue 是一个支持组件化开发的前端框架
vue 中规定:组件的后缀名是 .vue。之前接触到的 App.vue 文件本质上就是一个 vue 的组件。

4.3. vue 组件的三个组成部分

每个 .vue 组件都由 3 部分构成,分别是:

  • template -> 组件的模板结构
  • script -> 组件的 JavaScript 行为
  • style -> 组件的样式
    其中,每个组件中必须包含 template 模板结构,而 script 行为和 style 样式是可选的组成部分。
<template>
  <div>
    <div class="test-box">
      <h3>这是用户自定义的 Test.vue --- {{ username }}</h3>
    </div>
    <div>123</div>
  </div>
</template>

<script>
// 默认导出。这是固定写法!
export default {
  // data 数据源
  // 注意:.vue 组件中的 data 不能像之前一样,不能指向对象。
  // 注意:组件中的 data 必须是一个函数
  data() {
    // 这个 return 出去的 { } 对象中,可以定义数据
    return {
      username: 'admin'
    }
  },
 }
</script>

<style >
  background-color: pink;
</style>

4.3.1 template

vue 规定:每个组件对应的模板结构,需要定义到