快速上手 Vue.js <一>

本周做项目用到了 vue,周末复习整理一下~

在这里插入图片描述

一、Vue.js 介绍

1.1 认识 Vue

  • 一套用于构建用户界面的渐进式 JavaScript 框架
    • 在项目中一点点来引入和使用 vue
    • 大部分是用 vue 开发整个项目
  • 全称是 vue.js
  • 基于标准 HTML.CSS.JavaScript 构建,并提供了一套声明式的组件化的编程模型
  • 本质是一个 JavaScript 库,已经帮助我们封装好的库

1.2 Vue3

  • 2020 年 9 月 19 日,One piece 发布
  • 具有更好的性能
  • 更小的包体积
  • 更好的ts集成
  • 更优秀的 api 设计

1.3 使用 vue

  • 安装和使用 vue 和 JavaScript 库
    • 方式一:在页面中通过 CDN 的方式来引入
    • 方式二:下载 Vue 的 JavaScript文件,自己手动导入
    • 方式三:通过 npm 包管理工具安装使用它
    • 方式四:直接通过 Vue CLI(脚手架)创建项目,并且使用它

1.4 CDN 引入

  • 全局变量 Vue、函数 createApp、参数传入对象

  • 在模板 template 里面编写 html

  • data:funcition(){return{titile:“hahh”}} 这个函数会返回一个新的对象

  • 使用 const app 接收

  • 这个对象使用挂载方法:参数为挂载到哪里:使用 #+id

  • 底层是 querySelector

  • vue:将 template 里面的内容挂载到对应元素里面

  • 本地引入 ctrl+a:全选 下载复制代码到 lib/vue.js

    • script 引入

1.5 初体验

1.5.1 动态数据

  • 在 createApp 的参数是一个对象,对象可以有多个属性:template、data(必须是一个函数,返回值是一个对象,对象里面可以包含属性)
  • 差值语法:将某一个属性的值插入到 template 属性的内容里面来{{属性}}
  • 开发启示:
    • 以后开发先到服务器里面请求下来一些数据放到 data 函数里面的返回的对象里面
    • 通过语法动态插入到模板里面,不需要手动操作 dom(声明式开发),而是交给 vue 自己操作dom
 <div id="app"></div>
  <script src="./lib/vue.js"></script>
<script>
    const app = Vue.createApp({
      template: `<h2>{{title}}</h2> <h1>{{message}}</h1>`,
      data: function () {
        return {
          title: "hello world",
          message: "你好呀这是美好的今天!"
        }
      }
    })
    app.mount("#app")
  </script>

1.5.2 列表数据

  • <li v-for=“item in movies”>{{item}}
<body>
  <div id="app"></div>
  <script src="./lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      template: `
        <h2>{{message}}</h2>
        <h1>电影列表</h1>
        <ul>
          <li v-for="item in movies">{{item}}</li>  
        </ul>
      `,
      data: function () {
        return {
          message: "是一个优秀的孩子",
          movies: ["aaaaaa", "bbbbbbb", "gggggggggg", "ttttttttttt", "ooooooooo"]
        }
      }
    })
    app.mount("#app")
  </script>
</body>

1.5.3 计数器

  • createApp方法里面的第三个属性:method
  • methods 是一个对象:里面可以写很多方法,对 template 里面的元素进行操作
  • 直接使用 this 进行操作,如 this.counter
    • this 之所以能够找到那个对象是底层使用 bind 进行操作的
    • 直接修改 data 中的数据
<body>
  <div id="app"></div>
  <script src="./lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      template: `
        <h1>当前计数:{{counter}}</h1>
        <button @click="increment">+1</button>
        <button @click="decrement">-1</button>
      `,
      data: function () {
        return {
          counter: 0
        }
      },
      methods: {
        increment() {
          console.log("+1");
          this.counter++
        },
        decrement() {
          console.log("-1");
          this.counter--
        }
      }
    })
    app.mount("#app")
  </script>
</body>

1.6 声明式 vs 命令式

  • 声明式关注 what to do:剩下的交给框架

    • 声明一个模板
    • 声明 data
    • 声明 methods
    • 不用管怎么实现的
    • 会在createApp 传入的对象中声明需要的内容,模板 template、数据 data、方法 methods
    • 这样的编写代码的过程,称之为是声明式编程
    • 目前 Vue、React、Angular、小程序的编程模式,称之为声明式编程
  • 命令式

    • 命令式编程关注的是 “how to do”自己完成整个 how 的过程
    • 每完成一个操作,都需要通过 JavaScript 编写一条代码,来给浏览器一个指令;
      • 这样的编写代码的过程,称之为命令式编程
    • 在早期的原生 JavaScript 和 jQuery 开发的过程中,都是通过这种命令式的方式在编写代码的
<body>
  <h2>当前计数:<span class="counter"></span></h2>
  <button class="add">+1</button>
  <button class="sub">-1</button>
  <script>
    // 1. 获取dom
    const h2El = document.querySelector("h2")
    const counterEl = document.querySelector(".counter")
    const addBtnEl = document.querySelector(".add")
    const subBtnEl = document.querySelector(".sub")
    // 2. 定义一个变量记录数据
    let counter = 100
    counterEl.textContent = counter
    // 3. 监听按钮的点击
    addBtnEl.onclick = function () {
      counter++
      counterEl.textContent = counter
    }
    subBtnEl.onclick = function () {
      counter--
      counterEl.textContent = counter
    }
  </script>
</body>

1.7 MVVM 模型

  • 是一种软件的体系结构
    • Model View ViewModel
  • MVC在前端的应用
    • html–》view
    • javascript–》controller
  • Vue 是一个 MVVM 的框架,但是官方说它并没有完全遵守 MVVM 的模型,但是整个设计是受到它的启发的
    • view 里面写上特定的语法(eg:{{}},@click)
    • vue 内部帮助你把这个数据绑定上去 data binding,vue 框架帮你绑定整个 dom listener
  • Vue 相当于一个 ViewModel,在 view 视图和 Model 之间建立联系,来回进行数据沟通,沟通桥梁
  • View:div
  • Model:script
  • Vue 的底层操作 dom

1.8 data属性

  • vue2 的时候可以传入一个对象
  • vue3 规定必须传入一个函数,该函数需要返回一个对象
  • data 中返回的对象会被 Vue 的响应式系统劫持,被添加到 vue 的响应式系统中,之后对该对象的改修或者访问都会在劫持中被处理
    • 之后数据的一举一动都会被监听
    • vue2–》defineProperty
    • vue3–》new Proxy
  <div id="lili">{{message}}
    <button @click="changeText">改变文字</button>
  </div>
 
<script src="./lib/vue.js"></script>
<script>
  const app=Vue.createApp({
    data:function(){
      return{
        message:"hello lili"
      }
    },
    methods:{
      changeText:function(){
        this.message="你好"
        console.log("hahh");
      }
    }
  })
  app.mount("#lili")
</script>

1.9 methods 属性

  • methods 里面的 this 必须是有值的,通过 this 获取到 data 返回对象中的数据
  • 这个 this 不能是 window,在 window 中无法获取到 data 返回对象中的数据,使用箭头函数,这个 this 就是 window 了
  • methods 中不能使用箭头函数定义函数,找到的是上层作用域的 this:全局作用域 window
    • 里涉及到箭头函数使用 this 的查找规则,它会在自己的上层作用于中来查找 this
    • 最终刚好找到的是 script 作用于中的 this,所以就是window
  • this==》返回 proxy,vue 底层帮忙绑定了,所以它指向什么呢
    • 对 methods 中的所有函数进行了遍历,并且通过 bind 绑定了 this

二、Vue基础-模板语法(一)

2.1 模板语法

  • App.vue

    <template></template>
    <script></script>
    
  • react开发:

    • react 使用的 jsx:编写的类似于js的一种语法
    • 之后通过 Babel 将 jsx 编译成 React.createElement 函数调用
  • vue 开发

    • 也支持 jsx 开发

    • 基于 html 的模板语法

      <h2 v-bind v-for v-once>dafsf{{}}</h2>
      
    • 在 template 中允许开发者以声明式的方式将 dom 和底层组件实例的数据绑定在一起

    • 底层中将模板编译成虚拟 dom 渲染函数

2.2 Mustache 语法

  • 希望把数据显示到模板(template)中,使用最多的语法是 “Mustache”语法 (双大括号) 的文本插值

    • data 返回的对象是有添加到Vue的响应式系统中
    • 当 data 中的数据发生改变时,对应的内容也会发生更新
    • Mustache 中不仅仅可以是 data 中的属性,也可以是一个 JavaScript 的表达式
  • 差值语法、大胡子语法

  • 基本使用 {{counter}}

  • 表达式:{{counter*2}}

  • 三元运算符

  • 在里面不能定义语句

  • 调用 methods 里面的函数

<body>
  <div id="lili">
    <!-- 1. 基本使用 -->
    <h1> {{message}}</h1>
    <h2>当前计数:{{counter}}</h2>
    <!-- 2. 表达式 -->
    <h2>双倍计数:{{counter*2}}</h2>
    <h2>展示的信息:{{infos.split(" ")}}</h2>
    <!-- 3. 三元运算符 -->
    <h1>{{age>=18?"成年人":"小学生"}}</h1>
    <!-- 4. 调用methods中的函数 -->
    <h4>{{formatTime("yingyu")}}</h4>
    <!-- 5. 不能定义语句 -->
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili",
          counter: 0,
          infos: "my name is lili",
          age: 99
        }
      },
      methods:{
        formatTime(date){
          return "2023-5-16"+date
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

2.3 v-once 指令

  • 只会渲染一次,当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过
  • 子组件也不会重新渲染
  • 用于性能优化

2.4 v-text 指令

  • 会覆盖其他文本
<h2 v-text="message"></h2>
  • vs mustache

2.5 v-html 指令

  • 需要展示的内容包含 html,vue 是不会对其进行解析的
  • data函数返回的对象属性中包含的内容:content:html标签等等
  • 偶尔会用到
  <h1 v-html="content"></h1>

2.6 v-pre 指令

  • 不希望 vue 对{{}}进行解析
  • 就是 {{}}
  • v-pre 用于跳过元素和它的子元素的编译过程,显示原始的 Mustache 标签
  • 跳过不需要编译的节点,加快编译的速度

2.7 v-cloak 指令

  • clock:斗篷
  • 加上斗篷让你慢慢渲染
    • 因为有一些 vuejs 文件确实下载比较慢
    • 可能先把大胡子展现出来了
  • 需要结合 style 一起使用,将元素隐藏起来
<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>Document</title>
  <style>
    [v-clock] {
      display: none;
    }
  </style>
</head>
<body>
  <div id="lili">
    <h1 v-cloak>{{message}}</h1>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    setTimeout(() => {
      const app = Vue.createApp({
        data: function () {
          return {
            message: "hello lili"
          }
        }
      })
      app.mount("lili")
    }, 3000)
  </script>
</body>

2.7 v-memo 指令

  • 只更新绑定的值
<body>
  <div id="lili" v-memo="[name]">
    <p>{{message}}</p>
   <h2>姓名:{{name}}</h2>
   <h2>年龄:{{age}}</h2>
   <h2>身高:{{height}}</h2>
   <button @click="changeInfo">改变信息</button>
  </div>
 
<script src="../lib/vue.js"></script>
<script>
  const app=Vue.createApp({
    data:function(){
      return{
        message:"hello lili",
        name:"lili",
        age:99,
        height:1000
      }
    },
    methods:{
      changeInfo(){
        this.name = "kobe"
      }
    }
  })
  app.mount("#lili")
</script>
</body>

2.8 v-bind 绑定 属性

  • 希望动态来绑定某些属性
  • 绑定属性使用 v-bind
    • 缩写: :
    • 预期
    • 参数
    • 修饰符
    • 用法:动态地绑定一个或多个 attribute,或向另一个组件传递 prop 值
  • 语法糖:原来某种写法的简写
  • v-bind 用于绑定一个或多个属性值,或者向另一个组件传递 props 值
<body>
  <div id="lili">
    <!-- 切换图片 -->
    <!-- v-bind 语法糖:: -->
    <button @click="switchImage"></button>
    <!-- 1. 绑定img的src属性 -->
    <!-- 错误写法 -->
    <!-- <img src="{{imgURL}}" alt=""> -->
    <img v-bind:src=" showImgURL" alt="">
    <!-- 2. 绑定a的href -->
    <a v-bind:href="href">淘宝</a>


  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili",
          imgURL1: "http://baidu.com",
          imgURL2: "http://baiduuu.com",
          showImgURL: "http://baiduuu.com",
          href: "http://taobao.com"
        }
      },
      methods: {
        switchImage: function () {
          this.showImgURL = this.showImgURL === this.imgURL1 ? this.imgURL2 : this.imgURL1
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

2.9 绑定 class 全局属性

  • class 是动态的
  • 动态绑定 class 使用数组语法::class="[]"
    • 数组里面也可以加对象
  • 动态绑定 class 使用对象语法::class="{css名字:Boolean}"
    • value 对应 data 中定义的变量
    • 对象里面可以有多个属性
  • 动态绑定的 class 可以和普通的 class 一起使用
<body>
  <div id="lili">
    <!-- 1. 基本绑定 -->
    <h2 :class="classes">Hello lili</h2>
    <!-- 2. 三元运算符 -->
    <button :class="isActive? 'active' : ''" @click="btnClick">我是按钮yiyi</button>
    <!-- 3. 使用对象语法 -->
    <button :class="{active:isActive}" @click="btnClick">我是按钮erer</button>
    <!-- 4. 对象语法有多个键值对 -->
    <button :class="{active:isActive,lili:false,jiamiao:true}" @click="btnClick">我是按钮sansan</button>
    <!-- 5. 动态绑定的class是可以和普通的class同时使用 -->
    <button class="btn" :class="{active:isActive}">按钮sisi</button>
    <!-- 6. 使用方法返回对象 -->
    <button class="btn" :class="getDynamicClasses()" @click="btnClick">按钮wuwu
    </button>
    <!-- 7. 动态class可以写数组语法-->
    <h1 :class="['abc','cba','kkk']">我是一个大标题</h1>
    <!-- 8. 数组语法中可以写变量 -->
    <h2 :class="['bbb',className]">我是一个中标题</h2>
    <!-- 9. 数组中也可以使用对象 -->
    <h3 :class="['ccc',{'active':isActive}]">我是一个小标题</h3>
    <h3></h3>
  </div>

  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili",
          classes: "abc cba",
          isActive: false,
          className: 'nihao'
        }
      },
      methods: {
        btnClick() {
          this.isActive = !this.isActive
        },
        getDynamicClasses() {
          return { active: this.isActive }
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

2.10 绑定 style 属性

  • style=“{}”
  • 后面跟对象类型
  • 需要加引号表示一个整体或驼峰表示法
<body>
  <div id="lili">
    <!-- 1. 普通的html语法 -->
    <h1 style="color:red">哈哈哈哈</h1>
    <!-- 2. style中的某些值,来自于data中 -->
    <h1 :style="{color:fontColor,fontSize:fontsize}">哈哈哈哈</h1>
    <!-- 3. 动态板顶属性,该属性是一个对象 -->
    <h2 :style="styleObj">haahhhhhh</h2>
    <!-- 4. style的数组语法 -->
    <h1 :style="[styleObj,{backgroundColor:'blue'}]">你好呀</h1>
  </div>

  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili",
          fontColor: "blue",
          fontsize: "50px",
          styleObj: {
            color: "green"
          }
        }
      }
    })
    app.mount("#lili")

  </script>
</body>

2.11 动态绑定属性

  • 属性名不确定,可以动态绑定个属性名
  • class/style…不确定
  • :[属性名]=“aaa”
<body>
  <div id="lili">
    <h2 :[title]="'aaaa'">蛋白爱人</h2>
  </div>
  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili",
          title: "word"
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

2.12 绑定一个对象

  • 希望绑定多个属性,v-bind=某一个对象

  • <h2 v-bind="infos"></h2>
    
  • infos:{hah:88},info 对象会被拆解成 div 的各个属性

  • 经常用于给组件传递参数

<body>
  <div id="lili">{{message}}
    <!-- 一个一个地进行绑定 -->
    <h1 :name="name" :age="age" :height="height">hello lili</h1>
    <!-- 直接绑定对象:会自动遍历里面的所有属性,通常用于组件传值 -->
    <h1 v-bind="props">props</h1>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili",
          props: {
            name: 'lili',
            age: 12,
            height: 1.99
          },
          name: 'lili',
          age: 12,
          height: 1.99
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

2.13 v-on 绑定事件

  • 交互!!必须监听用户发生事件的监听,比如点击、拖拽、键盘事件
  • 使用 v-on 指令监听事件,@click 是语法糖,简写
  • 可以使用对象绑定多个事件
  • 修饰符
    • .stop - 调用 event.stopPropagation()
    • .prevent - 调用 event.preventDefault()
    • .capture - 添加事件侦听器时使用 capture 模式
    • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调
    • .{keyAlias} - 仅当事件是从特定键触发时才触发回调
    • .once - 只触发一次回调
    • .left - 只当点击鼠标左键时触发
    • .right - 只当点击鼠标右键时触发
    • .middle - 只当点击鼠标中键时触发
    • .passive - { passive: true } 模式添加侦听器  用法:绑定事件监听
<style>
    .box {
      width: 100px;
      height: 100px;
      background-color: orange;
      margin-top: 10px;
    }
  </style>
</head>
<body>


  <div id="app">
    <!-- 1.基本的写法 -->
    <div class="box" v-on:click="divClick"></div>
    <!-- 2.语法糖写法(重点掌握) -->
    <div class="box" @click="divClick"></div>
    <!-- 3.绑定的方法位置, 也可以写成一个表达式(不常用, 不推荐) -->
    <h2>{{ counter }}</h2>
    <button @click="increment">+1</button>
		<!-- 行内表达式 -->
    <button @click="counter++">+1</button>


    <!-- 4.绑定其他方法(掌握) -->
    <div class="box" @mousemove="divMousemove"></div>


    <!-- 5.元素绑定多个事件(掌握) -->
    <div class="box" @click="divClick" @mousemove="divMousemove"></div>
    <!-- <div class="box" v-on="{ click: divClick, mousemove: divMousemove }"></div> -->
    <!-- <div class="box" @="{ click: divClick, mousemove: divMousemove }"></div> -->
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data: function() {
        return {
          counter: 0
        }
      },
      methods: {
        divClick() {
          console.log("divClick")
        },
        increment() {
          this.counter++
        },
        divMousemove() {
          console.log("divMousemove")
        }
      }
    })


    // 2.挂载app
    app.mount("#app")
  </script>

2.14 绑定事件的参数传递

  • 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加

    • 但是注意:如果方法本身中有一个参数,那么会默认将原生事件 event 参数传递进去
  • 情况二:如果需要同时传入某个参数,同时需要 event 时,可以通过 $event 传入事件

  • 默认参数:event 对象

  • 绑定对象的时候没有任何的参数那么 event 对象会被默认传递进来

  • 不能理解成函数调用,vue 会在发生事件的时候传递参数

<div id="app">
    <!-- 1.默认传递event对象 -->
    <button @click="btn1Click">按钮1</button>


    <!-- 2.只有自己的参数 -->
    <button @click="btn2Click('wtthy', age)">按钮2</button>


    <!-- 3.自己的参数和event对象 -->
    <!-- 在模板中想要明确的获取event对象: $event -->
    <button @click="btn3Click('wtthy', age, $event)">按钮3</button>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data: function() {
        return {
          message: "Hello Vue",
          age: 18
        }
      },
      methods: {
        // 1.默认参数: event对象
        // 总结: 如果在绑定事件的时候, 没有传递任何的参数, 那么event对象会被默认传递进来
        btn1Click(event) {
          console.log("btn1Click:", event)
        },


        // 2.明确参数:
        btn2Click(name, age) {
          console.log("btn2Click:", name, age)
        },


        // 3.明确参数+event对象
        btn3Click(name, age, event) {
          console.log("btn3Click:", name, age, event)
        }
      }
    })


    // 2.挂载app
    app.mount("#app")
  </script>

2.15 v-on 修饰符

  • 修饰符:对事件做了一些特殊的处理
  • 阻止事件冒泡:@click.stop
  • 阻止默认行为:.prevent
  • 让事件传递变成捕获的模式:.capture
<body>
  <div id="lili">
    <div class="box" @click="divClick">
      <button @click.stop="btnClick">button</button>
    </div>
  </div>
  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili"
        }
      },
      methods: {
        divClick() {
          console.log("divClick");
        },
        btnClick() {
          console.log("btnClick");
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

2.16 条件渲染

  • 需要进行当前的条件来决定某些元素或组件是否渲染
  • v-if  v-else  v-else-if  v-show
  • 使用实例
<body>
  <div id="lili">
    <!-- v-if = "条件" -->
    <!-- 判断 对象 是否存在 -->
    <div class="info" v-if="Object.keys(info).length ">
      <h2>个人信息</h2>
      <ul>
        <!-- 之后使用v-for遍历对象 -->
        <li>姓名:{{info.name}}</li>
        <li>年龄:{{info.age}}</li>
      </ul>
    </div>
    <!-- v-else -->
    <div v-else>
      <h2>没有信息哦</h2>
    </div>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          info: {
            name: "lili",
            age: 12
          }
        }
      }
    })
    app.mount("#lili")
  </script>
</body>
<body>
  <div id="lili">
    <h1>你的分数:{{score}}</h1>
    <h2 v-if="score > 90">优秀</h2>
    <h2 v-else-if="score > 80">良好</h2>
    <h2 v-else-if="score >= 60">及格</h2>
    <h2 v-else>不及格</h2>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          score: 9
        }
      }
    })
    app.mount("#lili")
  </script>
</body>
  • 指令
    • v-if
    • v-else
    • v-else-if
    • v-show:频繁切换 显示、隐藏
  • v-if 是惰性的,当条件为 false 时,其判断的内容完全不会被渲染或者会直接被销毁

2.17 template 元素

  • 从浏览器性能来说,多加一个元素需要多创建一个元素对象,原本的div没有存在的必要,从而提高了浏览器性能

  • vue3 才支持 template

    • 目的就是为了把元素包裹在一起,不需要渲染 元素,作用就是为了在上面写指令
  • 类似于小程序的 block

  • 只是为了对指令做一个应用,与 v-if 结合使用

  • 如果 div 没有实际的意义,可以用 template 进行代替

2.18 点击元素的显示和隐藏

  • 通过控制变量进行修改
<body>
  <div id="lili">
    <div> <button @click="toggle">切换</button></div>
    <template v-if="isShowCode">
      <img src="https://game.gtimg.cn/images/yxzj/web201706/images/comm/floatwindow/wzry_qrcode.jpg" alt="">
    </template>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          isShowCode: true
        }
      },
      methods: {
        toggle() {
          this.isShowCode = !this.isShowCode
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

2.19 v-show 和 v-if 区别

2.19.1 v-show用法

  • 不支持 template
    • template 这个元素根本不存在,设置 display 没有用
  • 不能和 v-else 等一起使用

2.19.2 本质区别

  • v-show元素无论是否需要显示在浏览器上,它的DOM实际都是有存在的,只是通过 CSS 的display=none/block进行切换
  • v-if 条件为 false 时,其对应的元素根本不会被渲染到 DOM 中

2.19.3 开发选择

  • 元素需要在显示和隐藏之间频繁切换使用,使用 v-show
  • 不会频繁地发生切换,那么使用 v-if

三、Vue基础-模板语法(二)

3.1 列表渲染

  • 往往从服务器中获取的是一组数据,并且需要对其进行渲染
  • 使用 v-for 进行渲染,类似于 js 中的 for 循环

3.2 v-for基本使用

  • 基本格式 :v-for = “item in 数组”
    • 数组通常来自 data 或者 prop
  • 需要索引:(item,index)in 数组
  • 遍历数组
  • 遍历对象数组
  • 在哪个标签写就遍历谁,谁就出现多个
<div idli>
    <!-- 1. 电影列表进行渲染 -->
    <h2>1. 电影列表</h2>
    <ul>
      <li v-for="(item,index) in movies">{{index+1}}-{{item}}</li>
    </ul>
    <!-- 2. 遍历数组复杂数据 -->
    <h2>2. 商品列表</h2>
    <div v-for="item in products" class="item">
      <h3>商品:{{item.name}}</h3>
      <span>价格:{{item.price}}</span>
      <p>秒杀:{{item.desc}}</p>
    </div>
  </div>

3.3 v-for渲染类型

  • 数组
  • 对象
    • 默认写 item in info:item 是 value
    • (value,key,index)三个参数
  • 字符串
  • 数字:item in 100:从1~100
<body>
  <div id="lili">
    <!-- 1. 电影列表进行渲染 -->
    <h2>1. 电影列表</h2>
    <ul>
      <li v-for="(item,index) in movies">{{index+1}}-{{item}}</li>
    </ul>
    <!-- 2. 遍历数组复杂数据 -->
    <h2>2. 商品列表</h2>
    <div v-for="item in products" class="item">
      <h3>商品:{{item.name}}</h3>
      <span>价格:{{item.price}}</span>
      <p>秒杀:{{item.desc}}</p>
    </div>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          // 1. movies
          movies: ["aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg"],
          // 2. 数组中存放对象
          products: [
            { id: 110, name: "MacBook", price: 9.99, desc: "赶紧来买" },
            { id: 111, name: "note", price: 9.49, desc: "赶买" },
            { id: 310, name: "phone", price: 3.99, desc: "来买" },
            { id: 530, name: "Mac", price: 9.94, desc: "赶来买" },
            { id: 450, name: "Book", price: 1.99, desc: "赶紧" },
          ],
          message: "hello lili"
        }
      }
    })
    app.mount("#lili")
  </script>
</body>
<body>
  <div id="lili">
    <!-- 2. 遍历对象 -->
    <ul>
      <li v-for="(value,key,index) in info">{{value}}--{{key}}--{{index}}</li>
    </ul>
    <!-- 3. 遍历字符串 -->
    <ul>
      <li v-for="item in message">{{item}}</li>
    </ul>
    <!-- 4. 遍历数字 -->
    <ul>
      <li v-for="item in 100">{{item}}</li>
    </ul>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          info: {
            name: "lili",
            age: 23,
            height: 1.99
          }
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

3.4 数组更新检测

  • vue 将被侦听的数组的变更方法进行了包裹,所以它们也会触发视图更新
  • 方法
    • 创建一个新的数组
    • 通过数组的方法,修改数组中的元素
      • splice:删除
      • push
      • pop
      • sort
      • shift:删除第一个元素
      • unshift:添加元素
      • reverse
  • 不修改原数组的方法是不能侦听的,该方法是返回一个新数组,需要对原数组进行赋值 filter()、concat() 和 slice();
  • in===of
<script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          names: ["abc", "cba", "aaa", "bbb", "ccc"]
        }
      },
      methods: {
        changeArray() {
          // 1. 直接将数组修改给一个新的数组
          // this.names = ["why", "lili"]
          // 2. 通过一些数组的方法,修改数组中的元素
          // this.names.push("lili")
          // this.names.pop()
          // this.names.splice(2, 1, "hhh")
          // this.names.sort()
          // 3. 不修改原数组的方法不能监听(watch)
          // this.names.map(item => item + "lili")
          //需要重新赋值
          const newInfos = this.names.map(item => item + "lili")
          this.names = newInfos
        }
      }
    })
    app.mount("#lili")
  </script>

3.5 v-for 的 key 属性

  • 使用 v-for 进行列表渲染时候,vue 要求设置一个 key 属性
  • key 要求是唯一的,一般用id来绑定
  • :key=“”
  • key 属性主要用在 vue 的虚拟 dom 算法,在新旧 nodes 对比时辨识 VNodes ,找到哪个东西不一样,没有必要全部都修改
  • 比如在中间插入元素的时候,当没有设置 key 属性的时候,vue 修改的效率非常低,调用 patchUnkeyedChildren 方法,如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法,这样后面的都需要改了
    • 他不知道后面的元素可以重复应用
    • 如果后面绑定了 key,会识别到之前的节点和现在的节点是一样的,会进行复用
  • 有 key :源码通过调用 patchKeyedChildren方法,尽可能的进行复用这个节点,而不是移动或者创建新的节点
  • 使用时候加上key

3.6 认识VNode

  • 全称是 virtual Node,虚拟节点
  • 无论是组件还是元素,最终在Vue表现出来的都是一个个 VNode
  • 本质是 js 对象
  • 过程:template–》VNode(虚拟DOM)–》真实DOM

3.7 Vue 的虚拟 Dom

  • 不只是一个简单的 div 而是有一大堆的元素,多个VNode应该会形成一个 VNode Tree

  • 虚拟 dom 作用一:方便进行跨平台:通过虚拟dom根据不同渲染(浏览器、桌面端、移动端、VR设备)

    • 目的:跨平台,写一份应用到不同地方
  • 虚拟 dom 作用二:可以进行diff虚拟算法

    • 只需要在中间插入fff即可
    • 其他的节点都进行复用

四、Options API

4.1 复杂 data 的处理方式

  • 在模板中可以直接通过插值语法显示一些 data 中的数据

  • 需要对多个 data 数据进行运算、三元运算符来决定结果、多个数据进行转换、结合起来进行显示

  • 在模板中放入太多的逻辑会让模板阅读性不强,模板过重,难以维护

  • 在真实开发里面,某一些数据,需要一系列操作之后才能显示出来,并不是直接显示出来,需要进行一系列的运算

  • 将逻辑抽离出去:

    • method:只想要 fullname,却需要进行方法调用,加了小括号,看着不舒服
    • computed 登场

4.2 computed 属性

  • 对于任何包含响应式数据的复杂逻辑,都应该使用计算属性
  • 在使用数据时候需要进行某种变换都需要使用计算属性
  • 计算属性将被混入到组件实例中
    • 所有 getter 和 setter 的 this 上下文自动地绑定为组件实例
  • 计算属性更加见名知意
  • 和 method 的区别
    • computed 底层会缓存, 性能更高
    • 计算属性会基于它们的依赖关系进行缓存;
    • 在数据不发生变化时,计算属性是不需要重新计算的
    • 但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算

4.3 计算属性的缓存

  • 基于他们的依赖关系进行缓存
  • 当依赖的数据不发生变化的时候,计算属性是不需要重新计算的
  • 如果依赖的数据发生变化,使用时,计算属性依然会重新计算,但是只刷新一次

4.4 计算属性的 set 和 get 写法

  • Vue 源码内部只是做了一个逻辑判断而已
<script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          firstname: "lili",
          lastname: "luelue"
        }
      },


      computed: {
        // 等同于
        // 语法糖的写法
        // fullname() {
        //   return this.firstname + " " + this.lastname
        // },
        // 完整写法
        fullname: {
          get: function () {
            return this.firstname + " " + this.lastname
          },
          // 给计算属性设置值
          set: function (value) {
            const names = value.split(" ")
            this.firstname = names[0]
            this.middlename = names[1]
            this.lastname = names[2]
          }
        }
      },
      methods: {
        setFullname() {
          this.fullname = "lili aiiii jiji"
        }
      }
    })
    app.mount("#lili")
  </script>

4.5 侦听器 watch

  • 希望在代码逻辑中监听数据的变化,需要用侦听器 watch 来完成了
  • 当数据变化时,template 会自动进行更新来显示最新的数据
  • 当 template 中发现数据经过一些变化之后,需要去执行一些逻辑(打印,发送网络请求)
  • 监听 data/props 中的数据的变化:watch
<script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          info: { name: "ysy", age: 22 }
        }
      },
      methods: {
        changeMessage() {
          this.message = "你好啊",
            this.info = { name: "lili", age: 19 }
        }
      },
      watch: {
        // 1. 默认有两个参数:newValue/oldValue
        message(newValue, oldValue) {
          console.log("message数据发生变化", newValue, oldValue);
        },
        info(newValue, oldValue) {
          // 2. 对象返回的是proxy
          console.log("info数据发生变化",newValue,oldValue);
          // 3. 获取原始对象
          // 3.1 迭代方式:新的对象
          console.log({...newValue});
          // 3.2 Vue.toRaw:原来的值
          console.log(Vue.toRaw(newValue));
        }
      }
    })
    app.mount("#lili")
  </script>

4.6 method VS computed

  • 对数据的展示上
    • method
      • 事实上先显示的是一个结果,但是都变成了一种方法的调用
      • 多次使用方法的时候,没有缓存,也需要多次计算
    • computed
      • 使用的时候不需要加()
      • 是有缓存的

4.7 侦听器的配置选项

  • 希望用户在 input 中输入一个问题
    • 每当用户输入了最新的内容,就获取到最新的内容,并且使用该问题去服务器查询答案
    • 需要实时的去获取最新的数据变化
  • 例子
    • 当点击按钮的时候会修改 info.name 的值
      • 使用 watch 来侦听 info,不可以侦听
    • 这是因为默认情况下,watch 只是在侦听 info 的引用变化,对于内部属性的变化是不会做出响应的
    • 这个时候可以使用一个选项 deep 进行更深层的侦听
    • watch 里面侦听的属性对应的也可以是一个 Object
  • 还有另外一个属性,是希望一开始的就会立即执行一次: immediate 选项
  • 这个时候无论后面数据是否有变化,侦听的函数都会有限执行一次
  • 默认 watch 的监听是不会进行深度监听
<script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          info: {
            name: "why", age: 12
          }
        }
      },
      methods: {
        changeInfo() {
          // 1. 创建一个新对象,赋值给info
          // this.info = { name: "lili" }
          // 2. 直接修改原对象的某一个属性
          this.info.name = "lili"
        }
      },
      watch: {
        // info(newValue, oldValue) {
        //    默认watch的监听是不会进行深度监听的
        //   console.log("侦听到info改变", newValue, oldValue);
        // }


        // 进行深度监听
        info: {
          handler(newValue, oldValue) {
            // 用的还是同一个对象,改变的只是属性
            console.log("侦听到info改变", newValue, oldValue);
            console.log(newValue === oldValue);


          },
          // 监听器选项
          // info进行深度监听
          deep: true,
          // 第一次渲染直接执行一次监听器,oldValue为undefined
          immediate: true
        },
        // 单独监听一个属性
        'info.name': function (newValue, oldValue) {
          console.log(newValue, oldValue);
        }
      }
    })
    app.mount("#lili")
  </script>

4.8 侦听器 watch 的其他方式

<body>
  <div id="lili">{{message}}
    <button @click="changeMessage">修改message</button>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili"
        }
      },
      methods: {
        changeMessage() {
          this.message = "你好呀"
        }
      },
      // 生命周期回调函数:当前组件被创建时自动执行
      // 一般在该函数中,会进行网络请求
      created() {
        // ajax/fetch/axios
        this.$watch("message", (newValue, oldValue) => {
          console.log("message变化", newValue, oldValue);
        }, {
          deep: true
        })
      }
    })
    app.mount("#lili")
  </script>
</body>

4.9 购物车案例

<style>
    table {
      border-collapse: collapse;
    }


    th,
    td {
      padding: 8px 10px;
      text-align: center;
      border: 1px solid red;
    }


    .active {
      background-color: aquamarine;
    }
  </style>
</head>


<body>
  <div id="lili">
    <template v-if="books.length">
      <table>
        <thead>
          <tr>
            <th>序号</th>
            <th>书籍名称</th>
            <th>出版日期</th>
            <th>价格</th>
            <th>购买数量</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr :class="{active:index===curIndex}" @mouseover="mouseover(index)" v-for="(item,index) in books"
            :key="item.id">
            <td>{{index+1}}</td>
            <td>{{item.name}}</td>
            <td>{{item.date}}</td>
            <td>${{item.price}}</td>
            <td><button :disabled="item.count<=1" @click="decrease(index,item)">-</button>{{item.count}}<button
                @click="increase(index)">+</button></td>
            <td><button @click="removeBook(index)">移除</button></td>
          </tr>
        </tbody>


      </table>


      <h3>总价:${{price}}</h3>
    </template>
    <template v-else>
      <h2>快买</h2>
    </template>
  </div>


  <script src="../lib/vue.js"></script>
  <script src="./data.js"></script>
  <script>
    const app = Vue.createApp({
      data: function () {
        return {
          message: "hello lili",
          books: books,
          curIndex: -1
        }
      },
      computed: {
        price() {
          let price = 0
          for (const item of this.books) {
            price += item.price * item.count
          }
          return price
        },


      },
      methods: {
        decrease(index, item) {
          console.log("-", index);
          let cur = this.books[index].count
          if (cur > 1) this.books[index].count--
        },
        increase(index) {
          console.log("-", index);
          this.books[index].count++
        },
        removeBook(index) {
          this.books.splice(index, 1)
        },
        mouseover(index) {
          this.curIndex = index
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

五、Vue 基础-v-model 表单

5.1 v-model 的基本使用

  • 表单提交
    • 登录、注册时候需要提交账号密码
    • 用户在检索、创建、更新时,需要提交一些数据
  • 在代码逻辑中获取到用户提交的数据,通常会使用 v-model 指令来完成
  • v-model 应用
    • 在表单 input、textarea、textarea、select 元素上创建双向数据绑定
      • 输入框一旦输入东西就会触发 v-on:input 事件
    • 会根据控件类型自动选取正确的方法来更新元素
    • 不过是一种语法糖
  • 原理
    • v-bind 绑定 value 属性的值
    • v-on 绑定 input 事件
<input v-model="searchText"/>
    //等价于
<input :value="searchText" @input="searchText = $event.target.value"/>
<body>
  <div id="lili">
    <!-- 1. 手动实现双向绑定 -->
    <!-- 用户名:<input type="text" :value="username" @input="userChange">
    密码:<input type="password" :value="password" @input=" pwdChange">
    <button>登录</button>
    <h1>用户名:{{username}}</h1>
    <h1>密码:{{password}}</h1> -->
    <!-- 2. v-model实现双向绑定 -->
    <!-- <input type="text" v-model="message">
    <h1>message:{{message}}</h1> -->




    <!-- 登录功能 -->
    <label for="account">
      账号:<input id="account" type="text" v-model="account" />


    </label>
    <label for="password">
      密码:<input id="password" type="password" v-model="password" />
    </label>
    <button @click="loginClick">登录</button>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          // 每次绑定都得写属性
          // username: "lili",
          // password: '123456',
          // message: "lilihhh"
          account: "",
          password: ""
        }
      },
      methods: {
        // 每次绑定都得写方法
        userChange(event) {
          this.username = event.target.value
        },
        loginClick() {
          const account = this.account
          const password = this.password
          // url发送网络请求
          console.log(account);
          console.log(password);
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

5.2 v-model 绑定 textarea

<body>
  <div id="lili">


    <textarea cols="30" rows="10" v-model="content"></textarea>
    <p>输入的内容:{{content}}</p>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          content: "hhhhhhhhh"
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

5.3 v-model 绑定 checkbox

  • v-model 绑定 checkbox:单个勾选框和多个勾选框
  • 单个勾选框
    • v-model 即为布尔值
    • 此时 input 的 value 属性并不影响 v-model 的值
  • 多个复选框
    • 当是多个复选框时,因为可以选中多个,所以对应的 data 中属性是一个数组
    • 当选中某一个时,就会将 input 的 value 添加到数组中
<body>
  <div id="lili">
    <!-- 1. checkbox单选框:绑定到属性中的值是一个Boolean-->
    <!-- value属性没有意义 -->
    <label for="agree">
      <input id="agree" type="checkbox" v-model="isAgree">同意协议
    </label>
    <h1>单选框:{{isAgree}}</h1>


    <!-- 2. checkbox多选框:绑定到属性中的值是一个Array -->
    <!-- 注意:在多选框当中,必须明确的绑定一个value值 -->
    <!-- 当选中你的时候,会自动将value值放在属性当中 -->
    <div class="hobbies">
      <h1>请选择你的爱好</h1>
      <label for="sing">
        <input value="sing" type="checkbox" id="sing" v-model="hobbies"></label>
      <label for="jump">
        <input value="jump" type="checkbox" id="jump" v-model="hobbies"></label>
      <h2>爱好:{{hobbies}}</h2>
    </div>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          isAgree: false,
          hobbies: []
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

5.4 v-model 绑定 radio

<div id="lili">
    <div class="gender">
      <label for="male">
        <input id="male" type="radio" v-model="gender" value=""></label>
      <label for="female">
        <input id="female" type="radio" v-model="gender" value=""></label>
      <h2>性别:{{gender}}</h2>
    </div>


  </div>

5.5 v-model 绑定 select

  • select 也分单选和多选两种情况
    • 单选:只能选中一个值
      • v-model 绑定的是一个值
      • 当选中 option 中的一个时,会将它对应的 value 赋值到 fruit 中
    • 多选:可以选中多个值
      • v-model 绑定的是一个数组
      • 当选中多个值时,就会将选中的 option 对应的 value 添加到数组 fruit 中
<body>
  <div id="lili">
    <!-- select的单选 -->
    <select v-model="fruit">
      <option value="apple">苹果</option>
      <option value="orange">橘子</option>
      <option value="banana">香蕉</option>
    </select>
    <h2>单选:{{fruit}}</h2>
    <hr>
    <!-- select的多选 -->
    <select multiple size="3" v-model="fruits">
      <option value="apple">苹果</option>
      <option value="orange">橘子</option>
      <option value="banana">香蕉</option>
    </select>
    <h2>多选:{{fruits}}</h2>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          fruit: "",
          fruits: []
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

5.6 v-model 的值绑定

  • 让用户选择的时候爱好是从服务器中拿到的,而不是手动写死的
  • 值绑定:数据可能来自服务器,先将值请求下来,绑定到 data 返回的对象中,再通过 v-bind 来进行值的绑定
<body>
  <div id="lili">


    <!-- select的多选 -->
    <select multiple size="3" v-model="fruits">
      <option :value="item.value" v-for="item in allFruits" :key="item.value">{{item.text}}</option>
    </select>
    <h2>多选:{{fruits}}</h2>
    <!-- checkbox值绑定 -->
    <div class="hobbies">
      <h1>请选择你的爱好</h1>
      <template v-for="item in allHobbies" :key="item.value">
        <label :for="item.value">
          <input type="checkbox" :id="item.value" v-model="hobbies" :value="item.value">{{item.text}}
        </label>
      </template>
      <h2>爱好:{{hobbies}}</h2>
    </div>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          allFruits: [
            { value: "apple", text: "苹果" },
            { value: "orange", text: "橘子" },
            { value: "banana", text: "香蕉" },


          ],
          fruits: [],
          // 爱好
          allHobbies: [
            { value: "sing", text: "唱" },
            { value: "sing", text: "唱" },
            { value: "sing", text: "唱" },
          ],
          hobbies: []
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

5.7 v-model 修饰符

  • lazy

    • 默认情况下,v-model 在进行双向绑定的时候,绑定的是 input事件
    • 加上 lazy 就将事件切换为 change事件,只有在提交时才会触发
  • number

    • 自动将内容转换为数字
    • 但建议使用 type = “number”
  • trim

    • 去除首尾的空格
  • 使用多个修饰符

<body>
  <div id="lili">
    <!-- 1. lazy:绑定change事件 -->
    <input type="text" v-model.lazy="message">
    <h1>message:{{message}}</h1>
    <!-- 2. number:自动将内容转换为数字 -->
    <input type="text" v-model.number="counter">
    <h2>counter:{{counter}}--{{typeof counter}}</h2>
    <input type="number" v-model="counter2">
    <!-- 3. trim: 去除首尾的空格 -->
    <input type="text" v-model.trim="content">
    <h1>{{content}}</h1>
    <!-- 4. 使用多个修饰符 -->
    <input type="text" v-model.trim.lazy="info">
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili",
          counter: 3,
          counter2: 2,
          content: "哈哈哈哈或",
          info: "厉害啊"
        }
      },
      watch: {
        content(newValue) {
          console.log(newValue);
        }
      }
    })
    app.mount("#lili")
  </script>
</body>

六、Vue 组件化基础-脚手架

6.1 人处理问题的方式

  • 任何一个人处理信息的逻辑能力都是有限的
  • 所以,当面对一个非常复杂的问题时,不太可能一次性搞定一大堆的内容
  • 但是,人有一种天生的能力,就是将问题进行拆解
  • 如果将一个复杂的问题,拆分成很多个可以处理的小问题,再将其放在整体当中,会发现大的问题也会迎刃而解

6.2 Vue 组件化开发思想

  • 将一个页面中所以后的处理逻辑全部放在一起。处理起来会变得非常复杂,而不利于后续的管理以及扩展
  • 将一个页面拆分成一个个小的功能块,每一个功能块完成术语自己这部分独立的功能,像搭积木一样组合在一起
  • 三大框架、Flutter、移动端、小程序的开发
  • 页面
    • 拆分成哪些组件
    • 每一个组件需要实现哪一些功能
    • 每个组件又可以进行细分
    • 组件本身又可以进行复用
  • Vue.createApp({}) 里面传入的对象是一个根组件
  • 组件树
  • 相同逻辑的的东西抽取成一个组件
  • 对象就是组件

6.3 注册 Vue 的全局组件

  • 注册组件:
    • 全局组件:在任何其他的组件中都可以使用的组件,任何地方都可以进行使用
    • 局部组件:只有在注册的组件中才能使用的组件
<body>
  <div id="lili">


    <!-- 使用product-item组件 -->
    <product-item></product-item>
    <product-item></product-item>
    <product-item></product-item>
  </div>


  <script src="../lib/vue.js"></script>
  <script>
    // 1. 组件:App组件(根组件)
    const App = {
      data() {
        return {
          title: "hello lili",
          content: "我是内容哈哈哈哈"
        }
      }
    }
    // 2. 开发product-item组件
    const productItem = {
      template: `
    <div class="product">
      <h2>{{title}}</h2>
      <p>{{content}}</p>
      <div>商品图片</div>
      <div>商品价格:<span>¥9.9</span></div>
      <p>商品描述信息,9.9秒杀</p>
    </div>
      `
    }//必须注册才能够使用
    // 3. 创建app
    const app = Vue.createApp(App)
    // 4. 注册一个全局组件
    app.component("product-item", productItem)
    // 5. 挂载app
    app.mount("#lili")
  </script>
</body>

<body>
  <div id="lili">
    <product></product>
    <product></product>
    <product></product>
  </div>
  <template id="items">
    <div class="item">
      <h2>woshishangping</h2>
      <h3>shangpingtupian</h3>
      <h4>shangpingmiaoshuxinxi</h4>
    </div>
  </template>
  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp(App)
    const App = {}
    const productItem = {
      template: "#items"
    }


    app.component("product", productItem)
    app.mount("#lili")
  </script>
</body>

6.4 注册全局组件

  • app 中有一个方法,用来注册一个全局组件:app.component("product-item",productItem)// 组件名称 具体的对象
    • 组件(对象)里面是什么东西,product-item 里面就会渲染出什么东西
    • 可以在任意的其他组件的 template 中使用
  • 缺点:某些组件并没有用到,但是会被一起注册,类似于 webpack 这种打包工具在打包项目时,依然会对其进行打包,用户在下载对应的 js 会增加包的大小
<body>
  <div id="lili">{{message}}
    <home-nav></home-nav>
    <product-item></product-item>
    <product-item></product-item>
    <product-item></product-item>
    <product-item></product-item>


  </div>
  <template id="product">
    <div class="product">
      <div>商品图片</div>
      <div>商品价格:<span>¥{{price}}</span></div>
      <p>商品描述信息,9.9秒杀</p>
    </div>
    <button @click="favorItem">收藏</button>
  </template>
  <template id="nav">
    <div class="nav">
      <h2>navvvvvvvvvvvvvvvv</h2>
    </div>


  </template>
  <script src="../lib/vue.js"></script>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili"
        }
      }
    })
    // 注册全局组件
    app.component("product-item", {
      template: "#product",
      data() {
        return {
          title: "我是商品的item",
          price: 99
        }
      },
      methods: {
        favorItem() {
          console.log("点击了收藏");
        }
      }
    })


    app.component("home-nav", {
      template: "#nav"
    })
    app.mount("#lili")
  </script>
</body>

6.5 组件的名称

  • 在通过 app.component 注册一个组件的时候,第一个参数是组件的名称,定义组件名的方式有两种
  • 短横线分割符 kebab-case
  • 大驼峰标识符 PascalCase
    • html 里面是不区分大小写的
    • 后面写在 template 里面,是可以的

6.6 注册局部组件

  • 通常采用局部注册
  • 组件打算在哪里被使用(哪一个大组件中使用)
  • 在根组件的 component 的 components 属性里面
    • 局部组件的名称:{template data }
  • 要想在局部组件里面使用局部组件,必须在局部组件中 components
  • 该 components 选项对应的是一个对象,对象中的键值对是 组件的名称: 组件对象
<body>
  <div id="lili">{{message}}
    <product-item></product-item>
    <home-nav>


    </home-nav>
  </div>
  <template id="product">
    <div class="product">
      <div>商品图片</div>
      <div>商品价格:<span>¥{{price}}</span></div>
      <p>商品描述信息,9.9秒杀</p>
    </div>
  </template>
  <template id="nav">
    <div class="nav">
      <h2>nnnnnnnnnnnnnnnnnnnavvvvvvvvvvvvvvvv</h2>
      <product-item></product-item>
    </div>


  </template>
  <script src="../lib/vue.js"></script>
  <script>
    const ProductItem = {
      template: "#product",
      data() {
        return {
          price: 99
        }
      }
    }
    const app = Vue.createApp({
      data() {
        return {
          message: "hello lili"
        }
      },
      // 告诉vue在这个组件里面会用到哪些别的组件
      components: {
        ProductItem
        ,
        HomeNav: {
          template: "#nav",
          components: {
            ProductItem
          }
        }
      }


    })
    app.mount("#lili")
  </script>
</body>

6.7 Vue 的开发模式

  • 每个组件都会有自己的模板、脚本逻辑、样式
  • script 在一个全局的作用域下,很容易出现命名冲突问题
  • 代码为了适配一些浏览器,必须使用es5语法
  • 编写完代码后,依然需要通过工具对代码进行建
  • 解决方法:通过后缀名为 .vue 的单文件组织来解决,并且可以使用打包工具 webpack 或者 vite 或者 rollup 生成普普通通的js对象

6.8 如何支持 SFC

  • single file component
  • 使用
    • 使用Vue CLI(脚手架)来创建代码环境,帮助我们做好了所有的配置选项,可以在其中直接使用 .vue 文件
    • 自己使用 webpack 或 rollup 或 vite 这类打包工具

6.9 Vue CLI 脚手架

  • 脚手架:帮助我们搭建项目的工具
  • 在 vue 项目中使用的就是vue脚手架
  • vue 的脚手架:Vue CLI
    • 命令行界面
    • 通过 CLI 选择项目的配置和创建出项目
    • 已经内置了webpack 相关的配置,不需要从 0 开始配置

6.10 Vue CLI安装和使用

  • 脚手架本身也是 npm 包,放在 npm registry 仓库里面
  • npm i 脚手架名字 全局安装
    • npm i @vue/cli -g
  • 查看脚手架版本:vue --version
  • 使用脚手架创建项目:vue create 01_product_demo

想支持哪些特性:image.png

image.png

image.png

要不要生成预设image.png

6.11 目录结构

image.png

6.12 jsconfig.json

  • VSCode 进行读取,给它更好的代码提示
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "baseUrl": "./",
    "moduleResolution": "node",
    "paths": {
      "@/*": ["src/*"],
      "utils/*": ["src/utils/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  }
}

  • 打包的时候从 main.js 文件开始
  • 多层嵌套配置别名:vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  configureWebpack: {
    resolve: {
      // 配置路径别名:@是已经配置好的路径别名,对应的是src路径
      alias: {
        'utils':"@/utils"
      }
    }
  }
})


  • 提示仍然不友好

6.13 引入的 vue 的版本

  • 做法一: App.vue文件 SFC

    • import {createApp} from ‘vue’
      • 不支持 template 选项
    • 有自己的作用域
    • runtime 版本
    • 使用 webpack 中的 vue-loader 帮助编译转化的过程,已经将 template 预先编译了
  • 做法二: 自己定义了一个对象:template/data/methods

    • import {createApp} from ‘vue/dist/vue.esm-bunder.js’
      • 由vue源码完成compile过程
    • runtime + compile
      • 标签元素compile==》createNode》Vnode》真实dom

6.14 Vue 文件 style 的作用域

  • 不设置默认是全局属性,都会生效
  • 设置 scoped,只针对于自己的作用域

6.15 Vue 项目的创建方式

  • Vue CLI:vue create

    • webpack
  • npm init vue@latest

    • 安装一个本地工具:create-vue
    • 使用create-vue创建一个vue项目
    • vite
  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值