codewhy_vue笔记01

codewhy_vue笔记01_第1张图片

codewhy_vue笔记01_第2张图片

Vue.js安装

codewhy_vue笔记01_第3张图片

codewhy_vue笔记01_第4张图片

codewhy_vue笔记01_第5张图片

这里我们使用方式二:

去官网,下载vue.js(开发版本)

image-20210630184703768

使用webstorm新建项目,然后新建js文件夹,把刚才下载的vue.js放到js文件夹下

codewhy_vue笔记01_第6张图片

修改数据

codewhy_vue笔记01_第7张图片

第一个vue代码

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>

<div id="app">{{message}}div>

<script src="../js/vue.js">script>
<script>
  //let(变量) const(常量)
  //new Vue,说明有一个function Vue()
  //声明式编程
  const app = new Vue({
    //用于挂载要管理的元素
    el:'#app',
    //定义数据
    data:{
      message:'你好呀,李银河!'
    }
  })

  //以上代码使用js实现(命令式编程)
  //1、创建div元素
  //2、定义一个变量叫message
  //3.将message变量放在前面的div元素中
  //4.修改message数据:
  //5.将修改后的数据再次替换到div元素
script>
body>
html>

vue列表展示

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<div id="app">
    <h1>{{movies[0]}}h1>
    <ul>
        <li v-for="item in movies">{{item}}li>
    ul>
div>

<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      movies: ['龙门飞甲','芳华','剑雨','盗梦空间']
    }
  })
script>
body>
html>

codewhy_vue笔记01_第8张图片

响应式添加数据

codewhy_vue笔记01_第9张图片

vue计数器实列

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<div id="app">
  <h2>当前计数:{{counter}}h2>
  
  <button v-on:click="counter++">+button>
  <button v-on:click="counter--">-button>

  
  <button v-on:click="add">+button>
  <button v-on:click="sub">-button>
div>

<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      counter: 0
    },
    //定义方法,函数
    methods: {
      add: function(){
        console.log("add被执行了!")
        //注意,在函数里使用data中变量时,不能直接使用变量名,如果使用变量名它就会默认去找全局变量
        //使用data中的变量时,因为这些变量都是在Vue对象中,可以使用Vue的实列app调用变量,但最推荐的方式是使用this(当前对象)
        this.counter++
      },
      sub: function(){
        console.log("sub被执行了!")
        this.counter--
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第10张图片

语法糖:v-on:click等价于@click

Vue中的MVVM

codewhy_vue笔记01_第11张图片

计数器中的MVVM

codewhy_vue笔记01_第12张图片

另外的写法:结构更加清晰(使用了代理)

codewhy_vue笔记01_第13张图片

vue中的参数:options

el:

codewhy_vue笔记01_第14张图片

data:组件的时候必须传Function

function:函数:全局的function就是函数

方法:与类挂钩,类中的function是方法,即方法与类的实列挂钩

Vue的声明周期:

回调函数:

codewhy_vue笔记01_第15张图片

Vue自动回调函数

codewhy_vue笔记01_第16张图片

一般在created中做一些网络请求

codewhy_vue笔记01_第17张图片

codewhy_vue笔记01_第18张图片

codewhy_vue笔记01_第19张图片

代码规范:缩进两个空格

cli->.editconfig

webstorm中设置

codewhy_vue笔记01_第20张图片

codewhy_vue笔记01_第21张图片

编写自己的模板

<div id="app">
    {{message}}
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>

复制以上代码,点击设置->Editor->Live Templates->Vue

codewhy_vue笔记01_第22张图片

点击+号

codewhy_vue笔记01_第23张图片

点击Define

codewhy_vue笔记01_第24张图片

点击HTML,点击apply,点击应用,以后在html中输入vue后tab键即可弹出我们刚才定义的模板。、

codewhy_vue笔记01_第25张图片

tab键可以自定义为自己喜欢的方式

codewhy_vue笔记01_第26张图片

基本语法

模板语法

插值操作:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h2>{{message}}h2>
  <h2>{{message}},李银河h2>
  
  <h2>{{firstName + lastName}}h2>
  <h2>{{firstName + ' ' + lastName}}h2>
  <h2>{{firstName}} {{lastName}}h2>
  <h2>{{counter * 2}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      firstName: 'kobe',
      lastName: 'bryant',
      counter: 100
    }
  })
script>
body>
html>

codewhy_vue笔记01_第27张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h2>{{message}}h2>
  
  <h2 v-once>{{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

v-once

codewhy_vue笔记01_第28张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <h2>{{url}}h2>
  
  <h2 v-html="url">h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      url: '百度一下'
    }
  })
script>
body>
html>

codewhy_vue笔记01_第29张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
   <h2> {{message}}h2>
  
  <h2 v-text="message">h2>
  
  <h2 v-text="message">,李银河h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

第三个v-text后的,李银河被覆盖了

codewhy_vue笔记01_第30张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h2>{{message}}h2>
  
  <h2 v-pre>{{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

codewhy_vue笔记01_第31张图片

v-cloak:cloak(斗篷)

v-cloak加上css代码可以防止网络抖动时js代码执行缓慢导致的显示{{message}},而不是输出内容的情况,如模拟网络延时时

codewhy_vue笔记01_第32张图片

这是,就会出现上面的情况,1s后js解析完成,才能正常显示,使用v-cloak指令,让网络延时时什么也不显示

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
  <style>
      /*设置v-cloak的样式*/
    [v-cloak]{
        display: none
    }
  style>
head>
<body>
<div id="app">
  <h2 v-cloak>{{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
  //设置网络延时1秒后执行function函数
  //v-cloak:在vue解析之前,div中有一个属性,v-cloak
  //在vue解析完成后,div中没有属性v-cloak(即vue解析完成后会自动删除v-cloak-->
  setTimeout(function(){
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好呀'
      }
    })
  },1000)
script>
body>
html>

这时,vue解析延时时,会展示空白(即什么也不展示)

v-bind:绑定属性,即把数据绑定到属性中

使用mustache语法,直接在src中显示{{imgUrl}}

codewhy_vue笔记01_第33张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>

<div id="app">
  
  
  
  <img v-bind:src="imgUrl" alt="">
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      //图片地址,网上随便找的
      imgUrl: 'https://scpic.chinaz.net/files/pic/pic9/202106/apic33584.jpg'
    }
  })
script>
body>
html>

codewhy_vue笔记01_第34张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>

<div id="app">
  
  
  
  <img v-bind:src="imgUrl" alt="">
  <a v-bind:href="aHref">百度一下a>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      //图片地址,网上随便找的
      imgUrl: 'https://scpic.chinaz.net/files/pic/pic9/202106/apic33584.jpg',
      aHref: 'http:www.baidu.com'
    }
  })
script>
body>
html>

v-bind的语法糖:v-bind等价于:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
  <style>
    .actives{
        color: red;
    }
  style>
head>
<body>
<div id="app">
  <h2 :class="active">{{message}}h2>
  
  
  
  <h2 class="title" v-bind:class="{actives: isActive, line: isLine}">{{message}}h2>
  <button @click="btnClick">改变颜色button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      active: 'actives',
      isActive: true,
      isLine: true
    },
    methods: {
      btnClick: function(){
        this.isActive = !this.isActive
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第35张图片

{}对象使用函数返回

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
  <style>
    .actives{
        color: red;
    }
  style>
head>
<body>
<div id="app">
  <h2 class="title" :class="{actives: isActive, line: isLine}">{{message}}h2>
  
  <h2 class="title" :class="getClass()">{{message}}h2>
  <button @click="btnClick">改变颜色button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      isActive: true,
      isLine: true
    },
    methods: {
      btnClick: function(){
        this.isActive = !this.isActive
      },
      getClass: function(){
        return {actives: this.isActive, line: this.isLine}
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第36张图片

数组语法:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>

<div id="app">
  
  <h2 class="title" :class="['actives','line']">{{message}}h2>
  
  <h2 class="title" :class="[class1,class2]">{{message}}h2>
  
  <h2 class="title" :class="getClass()">{{message}}h2>
  
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      class1: 'actives',
      class2: 'line'
    },
    methods: {
      getClass: function(){
        return [this.class1, this.class2]
      }
    }
  })
script>
body>
html>

效果是一样的

codewhy_vue笔记01_第37张图片

作业需求:

点击列表中的某一项,那个该项文字变成红色:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>

<div id="app">
  <ul>
    
    <li v-for="(item,index) in movies">{{index + '-' + item}}li>
  ul>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      movies: ['海王','海尔兄弟','火影忍者','进击的巨人']
    }
  })
script>
body>
html>

v-bind动态绑定style

对象语法:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <h2 :style="{'font-size': '50px'}">{{message}}h2>
  
  <h2 :style="{fontSize: '50px'}">{{message}}h2>
  <h2 :style="{'fontSize': '50px'}">{{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

效果一样:

codewhy_vue笔记01_第38张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <h2 :style="{'font-size': '50px'}">{{message}}h2>
  
  <h2 :style="{fontSize: '50px'}">{{message}}h2>
  <h2 :style="{'fontSize': '50px'}">{{message}}h2>
  
  <h2 :style="{fontSize: finalSize}">{{message}}h2>
  <h2 :style="{fontSize: finalSize01 + 'px'}">{{message}}h2>
  <h2 :style="{fontSize: finalSize01 + 'px', color: finalColor}">{{message}}h2>
  <h2 :style="{fontSize: finalSize01 + 'px', background: finalColor}">{{message}}h2>
  
  <h2 :style="getStyles()">{{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      finalSize: '100px',
      finalSize01: 100,
      finalColor: 'red'
    },
    methods: {
      getStyles: function(){
        return {fontSize: this.finalSize01 + 'px', background: this.finalColor};
      }
    }
  })
script>
body>
html>

数组语法:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <h2 :style="[baseStyle, fontSize]">{{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      baseStyle: {background: 'red'},
      fontSize: {fontSize: '50px'}
    }
  })
script>
body>
html>

一、Vue基础语法

1、计算属性

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h2>{{firstName}} {{lastName}}h2>
  <h2>{{firstName + ' ' + lastName}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Lebron',
      lastName: 'James'
    }
  })
script>
body>
html>

上面的代码弊端:如果要写多次,就需要拼接多次,工作量大

codewhy_vue笔记01_第39张图片

解决办法一:使用方法

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h2>{{firstName}} {{lastName}}h2>
  <h2>{{firstName + ' ' + lastName}}h2>
  
  <h2>{{getFullName()}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Lebron',
      lastName: 'James'
    },
    methods: {
      getFullName(){
        return this.firstName + ' ' + this.lastName
      }
    }
  })
script>
body>
html>

解决办法二:使用计算属性:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h2>{{firstName}} {{lastName}}h2>
  <h2>{{firstName + ' ' + lastName}}h2>
  
  <h2>{{getFullName()}}h2>
  
  <h2>{{fullName}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Lebron',
      lastName: 'James'
    },
    methods: {
      getFullName(){
        return this.firstName + ' ' + this.lastName
      }
    },
    computed: {
      //类似于函数的定义,只不过这里使用的名词形式的函数名,即名字尽量使用名词,定义后是把它当作一个属性去使用,而不是函数
      fullName: function(){
        return this.firstName + ' ' + this.lastName
      }
    }
  })
script>
body>
html>

计算属性的应用场景:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <h2>总价格:{{totalPrice}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      books: [
        {
          id: 110, name: 'Unix编程艺术', price: 119
        },
        {
          id: 112, name: 'java编程艺术', price: 120
        },
        {id: 113, name:'深入计算机原理', price: 130},
        {id: 114, name: '代码大全', price: 140},
        {id: 115, name: '现代操作系统', price: 88}
      ]
    },
    //使用计算属性,计算总价格
    computed: {
      totalPrice: function(){
        let result = 0
        for(let i=0; i<this.books.length; i++){
          result += this.books[i].price
        }
          //或者
        /*for(let book of this.books){
          result += book.price
        }*/
        return result;
      }
    }
  })
script>
body>
html>

计算属性,在html中多次调用时,只执行一次,而函数没调用一次就执行一次,所以计算属性的执行效率更高。

codewhy_vue笔记01_第40张图片

Vue Day01回顾:

一、邂逅Vuejs

1.1.认识vuejs

  • 为什么学习vuejs
  • Vue读音
  • vue的渐进式
  • Vue的特点

1.2.安装vue

  • CDN引入
  • 下载引入
  • npm安装

1.3.vue初体验

  • Hello vuejs

    • mustache->体验vue响应式
  • vue列表展示

    • v-for
    • 后面给数组追加元素的时候,新的元素也可以在界面中渲染出来
  • Vue计数器小案例

1.4.vue中的MVVM

1.5.创建vue时,options可以放哪些东西

  • el
  • data
  • methods
  • 声明周期函数

二、插值语法

  • mustache语法
  • v-once
  • v-html
  • v-text
  • v-pre:{{}}
  • v-cloak:斗篷

三、v-bind

3.1.v-bind绑定基本属性

  • v-bind:src
  • v-bind:href

3.2.v-bind动态绑定class

  • 对象语法:class=’{类名:boolean}’
  • 数组语法:

3.3.v-bind动态绑定style

  • 对象语法
  • 数组语法

四、计算属性

  • 案例一:firstName + lastName
  • 案例二: books->price

1.2、计算属性的setter和getter

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <h2>{{fullName}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Kobe',
      lastName: 'Bryant'
    },
    computed: {
      //函数形式的写法
      /*fullName: function(){
        return this.firstName + ' ' + this.lastName;
      }*/
      //setter和getter写法 属性名:{} {}表示一个对象,对象中setter和getter方法
      fullName: {
        set: function(){

        },
        get: function(){
          //当我们使用计算属性的属性名时,本质就是来调用这个get方法
          return this.firstName + ' ' + this.lastName;
        }
      }

    }
  })
script>
body>
html>

注意:计算属性一般是不希望设置值的,即计算属性一般没有set方法,是一个只读属性

因为删除了set方法,所以计算属性有一种更为简洁的写法,如下:(即我们之前用的方法)

fullName: function(){

}

给计算属性赋值:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <h2>{{fullName}}h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Kobe',
      lastName: 'Bryant'
    },
    computed: {
      //函数形式的写法
      /*fullName: function(){
        return this.firstName + ' ' + this.lastName;
      }*/
      //setter和getter写法 属性名:{} {}表示一个对象,对象中setter和getter方法
      fullName: {
        set: function(newValue){
          //console.log('-----', newValue)
          const names = newValue.split(' ')
          this.firstName = names[0]
          this.lastName = names[1]
        },
        get: function(){
          //当我们使用计算属性的属性名时,本质就是来调用这个get方法
          return this.firstName + ' ' + this.lastName;
        }
      }

    }
  })
script>
body>
html>

codewhy_vue笔记01_第41张图片

计算属性的缓存

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <h3>{{firstName}} {{lastName}}h3>
  
  <h3>{{getFullName()}}h3>
  <h3>{{getFullName()}}h3>
  <h3>{{getFullName()}}h3>
  <h3>{{getFullName()}}h3>
  
  <h3>{{fullName}}h3>
  <h3>{{fullName}}h3>
  <h3>{{fullName}}h3>
  <h3>{{fullName}}h3>
  <h3>h3>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Lemon',
      lastName: 'Time'
    },
    //methods
    methods: {
      getFullName: function(){
        console.log('getFullName')
        return this.firstName + ' ' + this.lastName
      }
    },
    computed: {
      fullName: function(){
        console.log('fullName')
        return this.firstName + ' ' + this.lastName
      }
    }
  })
script>
body>
html>

可以看到methods打印了4次getFullName,而计算属性值打印了1次fullName,说明计算属性值执行了一次,之后再使用计算属性时,它直接把结果返回回来,而不会再去执行里面的操作(即直接返回return后的结果,里面的细节都不会再执行一次),但是返回值的计算表达式中的值发生了变化,计算属性还是会重新执行一次的,以保证结果的正确性

codewhy_vue笔记01_第42张图片

1.3、ES6语法

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<button>按钮1button>
<button>按钮2button>
<button>按钮3button>
<button>按钮4button>
<button>按钮5button>

<script>
  //1.变量作用域:变量在什么范围内起作用
  {
    var name = 'why';
    console.log(name)
  }
  //name在块外也起作用
  console.log(name)

  // 没有块级作用域引起的问题
  var func;
  if(true){
    var name = 'why';
    func = function(){
      console.log(name);
    }
  }
  //在调用func前修改了name的值
  name = 'Kobe';
  //打印的name不是我们希望的why,而是Kobe
  func()

  //没有块级作用域引起的问题: for的块级
  var btns = document.getElementsByTagName('button')
  //当我们点击按钮时,几乎都会输出'第5个按钮被点击了‘,原因跟上面的列子差不多,我们在事件监听的函数中使用的i是外部的i,由于
  //外部的i是增加事件监听的,执行的很快,于是i就被变为了5,当我们点击按钮的时候,执行事件监听的方法,于是i还是5
  for(var i = 0; i < btns.length; i++){
    btns[i].addEventListener('click', function(){
      console.log('第' + i + '个按钮被点击');
    })
  }
script>
body>
html>

codewhy_vue笔记01_第43张图片

以前为了解决这个问题,需要使用闭包

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<button>按钮1button>
<button>按钮2button>
<button>按钮3button>
<button>按钮4button>
<button>按钮5button>

<script>
  //函数的作用域
  var name = 'why'
  function abc(name){
    console.log(name)
  }
  //我们这里只是改变了函数外name的值,并不会影响形参的name,形参的name是我们传什么就是什么
  name = 'Kobe'
  abc('hello')

  //没有块级作用域引起的问题: for的块级
  var btns = document.getElementsByTagName('button')
  //使用闭包解决这个问题:
  //为什么闭包能解决这个问题:因为函数是一个作用域
  for(var i = 0; i < btns.length; i++){
    (function(i){
      btns[i].addEventListener('click', function(){
        console.log('第' + i + '个按钮被点击');
      })
    })(i)
  }
script>
body>
html>

codewhy_vue笔记01_第44张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<button>按钮1button>
<button>按钮2button>
<button>按钮3button>
<button>按钮4button>
<button>按钮5button>

<script>
  //函数的作用域
  var name = 'why'
  function abc(name){
    console.log(name)
  }
  //我们这里只是改变了函数外name的值,并不会影响形参的name,形参的name是我们传什么就是什么
  name = 'Kobe'
  abc('hello')

  //没有块级作用域引起的问题: for的块级
  var btns = document.getElementsByTagName('button')
  //使用闭包解决这个问题:
  //为什么闭包能解决这个问题:因为函数是一个作用域
  for(var i = 0; i < btns.length; i++){
    (function(num){
      btns[i].addEventListener('click', function(){
        console.log('第' + num + '个按钮被点击');
      })
    })(i)
  }
script>
body>
html>

ES6之前因为if和for都没有块级作用域的概念,所以在很多时候,我们必须借助于function的作用域来解决外面变量的问题。这个function一般是匿名function

使用let解决块级作用域:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<button>按钮1button>
<button>按钮2button>
<button>按钮3button>
<button>按钮4button>
<button>按钮5button>

<script>
  const btns = document.getElementsByTagName('button');
  for(let i=0;i<btns.length;i++){
    btns[i].addEventListener('click', function(){
      console.log('第' + i + '个按钮被点击');
    })
  }
script>

body>
html>

codewhy_vue笔记01_第45张图片

1.4、const的使用和注意点

在es6中,优先使用const,只有需要改变某一个变量是,才使用let

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<script>
  //正常定义对象
  // const obj = new Object()

  //字面量写法:{}就表示字面量
  //原来的写法
  /*const obj = {
    name: 'why',
    age: 18,
    run: function(){
      console.log('在奔跑')
    }*/

  // 1.属性的增强写法
  const name = 'why';
  const age = 18;
  const height = 180;
  // ES5的写法
  /*const obj = {
    name: name,
    age: age,
    height: height
  }*/
  // ES6的写法,他会把变量名作为key,把变量的value作为value
  const obj = {
    name,
    age,
    height,
  }
  console.log(obj)

  //2.函数的增强写法
  //ES5的写法
 /* const obj1 = {
    run: function(){

    },
    eat: function(){

    }*/
  // ES6的写法
  const obj1 = {
    run(){
      
    },
    eat(){
      
    }
  }
script>
body>
html>

1.5、v-on的使用

v-on:事件监听

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  

  
  <h3>{{counter}}h3>
  <button v-on:click="increment()">+button>
  <button v-on:click="decrement()">-button>
  
  <button v-on:click="increment">+button>
  <button v-on:click="decrement">-button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      counter: 0
    },
    methods: {
      increment(){
        this.counter++
      },
      decrement(){
        this.counter--
      }
    }
  })
script>
body>
html>

v-on的语法糖为:@

codewhy_vue笔记01_第46张图片

小括号可以省略的条件:事件监听中,调用的方法不需要传递参数


<button @click="btn3Click(123,event)">按钮6button>

codewhy_vue笔记01_第47张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <button @click="btn1Click()">按钮1button>
  
  <button @click="btn1Click">按钮2button>
  
  <button @click="btn2Click">按钮3button>
  
  <button @click="btn2Click(123)">按钮4button>
  
  <button @click="btn2Click()">按钮5button>

  
  <button @click="btn3Click(123,event)">按钮6button>
  
  <button @click="btn3Click(123,$event)">按钮6button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      event: 'Hello,你好'
    },
    methods: {
      btn1Click(){
        console.log('btn1Click');
      },
      btn2Click(param){
        console.log('-----', param, '------');
      },
      btn3Click(param, event){
        console.log('++++++', param,'event:', event);
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第48张图片

v-on的修饰符

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <div @click="divClick">
      按钮
      <button @click="btnClick">按钮button>
    div>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      divClick(){
        console.log("divClick");
      },
      btnClick(){
        console.log("btnClick");
      }
    }
  })
script>
body>
html>

当我点击button中的按钮时,由于事件冒泡的存在,divClick也被点击了

codewhy_vue笔记01_第49张图片

阻止事件冒泡:stop

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <div @click="divClick">
      按钮
      <button @click.stop="btnClick">按钮button>
    div>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      divClick(){
        console.log("divClick");
      },
      btnClick(){
        console.log("btnClick");
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第50张图片

prevent修饰符的使用:阻止默认事件的使用

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <div @click="divClick">
      按钮
      <button @click.stop="btnClick">按钮button>
    div>
  <br>
  
  <form action="baidu">
    <input type="submit" value="提交">
  form>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      divClick(){
        console.log("divClick");
      },
      btnClick(){
        console.log("btnClick");
      }
    }
  })
script>
body>
html>

点击按钮后,vue会自动提交:

image-20210707152832355

我们不希望使用vue的默认提交,需要使用自己定义的提交:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <div @click="divClick">
      按钮
      <button @click.stop="btnClick">按钮button>
    div>
  <br>
  
  <form action="baidu">
    <input type="submit" @click.prevent="submitClick" value="提交">
  form>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      divClick(){
        console.log("divClick");
      },
      btnClick(){
        console.log("btnClick");
      },
      submitClick(){
        console.log("submitClick");
      }
    }
  })
script>
body>
html>

现在就只打印,不提交,如果要提交的话,可以自己定义自己的请求

监听某个键盘的某个键的点击:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <div @click="divClick">
      按钮
      <button @click.stop="btnClick">按钮button>
    div>
  <br>
  
  <form action="baidu">
    <input type="submit" @click.prevent="submitClick" value="提交">
  form>

  
  <input type="text" @keyup="keyUp">
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      divClick(){
        console.log("divClick");
      },
      btnClick(){
        console.log("btnClick");
      },
      submitClick(){
        console.log("submitClick");
      },
      keyUp(){
        console.log("keyUp")
      }
    }
  })
script>
body>
html>

当键按下抬起时就会被监听到

codewhy_vue笔记01_第51张图片

只监听某个特殊的按键,如回车键:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <div @click="divClick">
      按钮
      <button @click.stop="btnClick">按钮button>
    div>
  <br>
  
  <form action="baidu">
    <input type="submit" @click.prevent="submitClick" value="提交">
  form>

  
  <input type="text" @keyup.enter="keyUp">
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      divClick(){
        console.log("divClick");
      },
      btnClick(){
        console.log("btnClick");
      },
      submitClick(){
        console.log("submitClick");
      },
      keyUp(){
        console.log("keyUp")
      }
    }
  })
script>
body>
html>

这时只有按下回车键才会被监听到

.once只触发一次回调

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
    <div @click="divClick">
      按钮
      <button @click.stop="btnClick">按钮button>
    div>
  <br>
  
  <form action="baidu">
    <input type="submit" @click.prevent="submitClick" value="提交">
  form>

  
  <input type="text" @keyup.enter="keyUp">

  
  <button @click.once="btn2Click">btn2button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      divClick(){
        console.log("divClick");
      },
      btnClick(){
        console.log("btnClick");
      },
      submitClick(){
        console.log("submitClick");
      },
      keyUp(){
        console.log("keyUp")
      },
      btn2Click(){
        console.log("btn2Click");
      }
    }
  })
script>
body>
html>

只有第一次点击才起作用

1.6、条件判断

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h3 v-if="isShow">
    <div>{{message}}div>
  h3>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      isShow: true
    }
  })
script>
body>
html>

codewhy_vue笔记01_第52张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h3 v-if="isShow">
    <div>abcdiv>
    <div>defdiv>
  h3>
  <h2 v-else>isShow为false时显示我h2>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      isShow: true
    }
  })
script>
body>
html>

codewhy_vue笔记01_第53张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h3 v-if="score>=90">优秀h3>
  <h3 v-else-if="score>=80">良好h3>
  <h3 v-else>一般h3>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      score: 99
    }
  })
script>
body>
html>

codewhy_vue笔记01_第54张图片

逻辑复杂的时候不建议这样做,如果逻辑复杂,最好使用计算属性的方式

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h3>{{showLevel}}h3>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      score: 99
    },
    computed: {
      showLevel(){
        if(this.score>=90){
          return '优秀';
        }
        else if(this.score>=80){
          return '良好';
        }
        else{
          return '一般';
        }
      }
    }
  })
script>
body>
html>

1.7、登录小案例

codewhy_vue笔记01_第55张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <span v-if="isUser">
    <label for="username">用户账号label>
    <input type="text" id="username" placeholder="用户账号">
  span>
  <span v-else>
    <label for="email">用户邮箱label>
    <input type="text" id="email" placeholder="用户邮箱">
  span>
  <button @click="isUser=!isUser">切换类型button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      isUser: true
    }
  })
script>
body>
html>

codewhy_vue笔记01_第56张图片

当前小案列的小问题:例如我在用户账号界面输入了一些东西,突然想到应该用邮箱登录,于是切换到用户邮箱界面登录,但切换到用户邮箱叫界面时,在用户账号界面输入的账号也会携带过去,并不会清空

codewhy_vue笔记01_第57张图片

切换

codewhy_vue笔记01_第58张图片

vue底层原理:虚拟DOM,尽可能复用(只修改不同的地方)

需求:切换时清除之前的输入:使用key做标识,只用key相同时,才会复用,如果key不相同,vue就不会复用

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <span v-if="isUser">
    <label for="username">用户账号label>
    <input type="text" id="username" placeholder="用户账号" key="username">
  span>
  <span v-else>
    <label for="email">用户邮箱label>
    <input type="text" id="email" placeholder="用户邮箱" key="email">
  span>
  <button @click="isUser=!isUser">切换类型button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      isUser: true
    }
  })
script>
body>
html>

1.8、v-show

v-show:和v-if一样,也可以决定一个元素是否渲染

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h3 v-if="isShow">{{message}}h3>
  <h3 v-show="isShow">{{message}}h3>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: "你好呀",
      isShow: true
    }
  })
script>
body>
html>

当为true时,两个显示效果一样

codewhy_vue笔记01_第59张图片

修改为false:两个都不显示

codewhy_vue笔记01_第60张图片

查看html源码:

codewhy_vue笔记01_第61张图片

v-if在显示同时,html源码中也没有相应代码,v-show只是添加了一个行内样式:display:none

1.9、循环遍历

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <ul>
    <li v-for="item in names">{{item}}li>
  ul>

  
  <ul>
    <li v-for="(item, index) in names">{{index+1}}-itemli>
  ul>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      names: ['why', 'who', 'what', 'whom', 'curry', 'lemon']
    }
  })
script>
body>
html>

在遍历的过程中,没有使用索引(下标值)

codewhy_vue笔记01_第62张图片

使用下标

codewhy_vue笔记01_第63张图片

v-for遍历对象:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <ul>
    <li>{{info.name}}li>
    <li>{{info.age}}li>
    <li>{{info.height}}li>
  ul>
  
  <ul>
    <li v-for="item in info">{{item}}li>
  ul>
  
  <ul>
    <li v-for="(value, key) in info">{{key}} - {{value}}li>
  ul>
  
  <ul>
    <li v-for="(value, key, index) in info">{{index}} - {{key}} - {{value}}li>
  ul>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      info: {
        name: 'why',
        age: 18,
        height: 188
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第64张图片

1.10、组件key的使用

codewhy_vue笔记01_第65张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <ul>
    <li v-for="item in letters">{{item}}li>
  ul>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      letters: ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    }
  })
script>
body>
html>

官方推荐使用v-for时添加key属性

splice():函数的使用:删除元素:splice(开始位置,删除元素的个数)

添加元素:splice(开始位置,0, 要添加的元素(如果要添加多个,以逗号分割)),splice(1),从第一个删到最后一个元素,即只留下第一个元素

替换元素:splic(开始位置,要替换元素的个数,要替换的元素(如果有多个,以逗号分割)):也可以理解为,先删除要替换元素的个数的元素,在插入要替换的元素

codewhy_vue笔记01_第66张图片

如果不加key,vue会从第二个位置开始替换,即把第二个位置改为F,第三个位置改为C,…,最后一个位置改为G,性能很低。

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <ul>
    
    <li v-for="item in letters" :kye="item">{{item}}li>
  ul>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      letters: ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    }
  })
script>
body>
html>

使用key时,vue会把key和要展示的元素一一对应,只要key对应的值不变,他就会不动,key不同的就会在创建一个key和值对应,然后再插入到正确的位置即可。

1.11、数组中有哪些方法是响应式的

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <ul>
    <li v-for="item in letters" :key="item">{{item}}li>
  ul>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      letters: ['a', 'c', 'd', 'e', 'f']
    }
  })
script>
body>
html>

push是响应式的:

codewhy_vue笔记01_第67张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <ul>
    
    <li v-for="item in letters">{{item}}li>
  ul>
  <button @click="btnClick">按钮button>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      letters: ['a', 'c', 'd', 'e', 'f']
    },
    methods: {
      btnClick(){
        // 1.push方法
        // this.letters.push('g');

        //2.通过索引值修改数组中的元素
        this.letters[0] = 'aaa';
      }
    }
  })
script>
body>
html>
通过索引值修改数组中的元素不能做到响应式点击并不会被修改

codewhy_vue笔记01_第68张图片

一下都是可以做到响应式的方法:

  • pop()

  • shift() 删除数组中的第一个元素

  • unshift() 在数组中的第一个位置加入元素,可以同时加入多个元

    image-20210707170427700

    codewhy_vue笔记01_第69张图片

  • splic()

  • sort()

  • reverse()

注意:通过索引值修改元素的值不是响应式的。

如果确实要修改,并且要把修改的结果渲染到界面,使用splice函数

也可以使用:Vue.set()函数,该函数时vue内部实现的一个函数

Vue.set(要修改的数组,修改的位置,要修改为什么值)

image-20210707171517650

1.12、作业的回顾和完成

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
  <style>
    .active{
        color: red;
    }
  style>
head>
<body>
<div id="app">
  <ul>
    <li v-for="(item, index) in movies"
        :class="{active: currentIndex === index}" @click="liClick(index)">
      {{index}}.{{item}}
    li>
  ul>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      movies: ['海王', '海贼王', '加勒比海盗', '海尔兄弟', '大海', '小海'],
      // 记录当前哪一个li标签显示红色
      currentIndex: 0
    },
    methods: {
      liClick(index){
        this.currentIndex = index;
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第70张图片

1.13、图书购物车案例

codewhy_vue笔记01_第71张图片

项目架构

image-20210707172914020

style.css

table {
    border: 1px solid #e9e9e9;
    border-collapse: collapse;
    border-spacing: 0;
}

th, td {
    padding: 8px 16px;
    border: 1px solid #e9e9e9;
    text-align: center;
}

th {
    background-color: #f7f7f7;
    color: #5c6b77;
    font-weight: 600;
}

main.js

const app = new Vue({
  el: '#app',
  data: {
    books: [
      {
        id: 1,
        name: '《算法导论》',
        date: '2006-9',
        price: 85.00,
        count: 1
      },
      {
        id: 2,
        name: '《Unix编程艺术》',
        date: '2006-2',
        price: 59.00,
        count: 1
      },
      {
        id: 3,
        name: '《编程珠玑》',
        date: '20027-3',
        price: 39.00,
        count: 1
      },
      {
        id: 4,
        name: '《代码大全》',
        date: '2010-6',
        price: 128.00,
        count: 1
      }
    ]
  }
})

index.html

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
  <link rel="stylesheet" href="style.css">
head>
<body>
<div id="app">
  <table>
    <thead>
    <tr>
      <th>th>
      <th>书籍名称th>
      <th>出版日期th>
      <th>价格th>
      <th>购买数量th>
      <th>操作th>
    tr>
    thead>
    <tbody>
    <tr v-for="item in books">
      <td v-for="value in item">{{value}}td>
    tr>
    tbody>
  table>
div>


<script src="../js/vue.js">script>
<script src="main.js">script>
script>
body>
html>

codewhy_vue笔记01_第72张图片

上面的代码对购买数量中的操作不好做,于是改为下面的方式:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
  <link rel="stylesheet" href="style.css">
head>
<body>
<div id="app">
  <table>
    <thead>
    <tr>
      <th>th>
      <th>书籍名称th>
      <th>出版日期th>
      <th>价格th>
      <th>购买数量th>
      <th>操作th>
    tr>
    thead>
    <tbody>
    <tr v-for="item in books">
      <td>{{item.id}}td>
      <td>{{item.name}}td>
      <td>{{item.date}}td>
      <td>{{item.price}}td>
      <td>
        <button>-button>
        {{item.count}}
        <button>+button>
      td>
      <td><button>移除button>td>
    tr>
    tbody>
  table>
div>


<script src="../js/vue.js">script>
<script src="main.js">script>
script>
body>
html>

codewhy_vue笔记01_第73张图片

细节处理:如价格保留两位小数和一个¥符号:方式一:toFixed()方法

<td>{{'¥' + item.price.toFixed(2)}}td>

方式二:methods方法

methods: {
  getFinalPrice(price){
    return '¥' + price.toFixed(2)
  }
}

使用:

<td>{{getFinalPrice(item.price)}}td>

方式三:过滤器

filters: {
  // 过滤器是一个函数
  showPrice(price){
    return '¥' + price.toFixed(2)
  }
}

使用:{{item.price | 过滤器}}

{{item.price | showPrice}}

添加和删除:

总价格:计算属性

最终:style.css没有变化

main.js

const app = new Vue({
  el: '#app',
  data: {
    books: [
      {
        id: 1,
        name: '《算法导论》',
        date: '2006-9',
        price: 85.00,
        count: 1
      },
      {
        id: 2,
        name: '《Unix编程艺术》',
        date: '2006-2',
        price: 59.00,
        count: 1
      },
      {
        id: 3,
        name: '《编程珠玑》',
        date: '20027-3',
        price: 39.00,
        count: 1
      },
      {
        id: 4,
        name: '《代码大全》',
        date: '2010-6',
        price: 128.00,
        count: 1
      }
    ]
  },
  methods: {
    /*getFinalPrice(price){
      return '¥' + price.toFixed(2)
    }*/
    increment(index){
      this.books[index].count++
    },
    // 移除
    decrement(index){
      this.books[index].count--
    },
    removeHandle(index){
      this.books.splice(index, 1)
    }
  },
  filters: {
    // 过滤器是一个函数
    showPrice(price){
      return '¥' + price.toFixed(2)
    }
  },
  computed: {
    totalPrice(){
      let totalPrice = 0
      for(let i = 0; i < this.books.length; i++){
        totalPrice += this.books[i].price * this.books[i].count;
      }
      return totalPrice
    }
  }
})

index.html

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
  <link rel="stylesheet" href="style.css">
head>
<body>
<div id="app">
  
  <div v-if="books.length">
    <table>
      <thead>
      <tr>
        <th>th>
        <th>书籍名称th>
        <th>出版日期th>
        <th>价格th>
        <th>购买数量th>
        <th>操作th>
      tr>
      thead>
      <tbody>
      <tr v-for="(item, index) in books">
        <td>{{item.id}}td>
        <td>{{item.name}}td>
        <td>{{item.date}}td>
        <td>{{item.price | showPrice}}td>
        <td>
          
          <button @click="decrement(index)" :disabled="item.count<=1">-button>
          {{item.count}}
          <button @click="increment(index)">+button>
        td>
        <td><button @click="removeHandle(index)">移除button>td>
      tr>
      tbody>
    table>
    <h3>总价格:{{totalPrice | showPrice}}h3>
  div>
  
  <h3 v-else>购物车为空......h3>
div>


<script src="../js/vue.js">script>
<script src="main.js">script>
script>
body>
html>

codewhy_vue笔记01_第74张图片

计算总价格也可以写为:

totalPrice(){
	let totalPrice = 0
	for(let book of this.books){
        totalPrice += book.price * book.count
    }
    return totalPrice
}

二、javaScript高阶函数的使用

数组操作的高级函数:

以前的编程范式:

  • 命令式编程
  • 声明式编程:

另一种分类方式:

  • 面向对象编程:谁是第一公民(对象)
  • 函数式编程:第一公民(函数),尽可能的把一些东西抽象程函数,函数式编程可以支持链式调用

例如:

const nums = [10, 20, 111, 222, 444, 40, 50]
// 需求1:取出所有小于100的数字
// 以前的方式
let newNums = []
for(let n of nums){
    if(n < 100){
        newNums.push(n)
    }
}

// 需求2:将所有小于100的数组*2
let new2Nums = []
for(let n of newNums){
    new2Nums.push(n * 2)
}

// 需求3:将所有的数字相加得到最终结果
let total = 0
for(let n of new2Nusm){
    total += n
}

以上的需求使用高级函数编程:filter(),他需要传一个回调函数(即传一个函数),该回调函数的执行节点:它会在每一次从数组中遍历出来一个数字的时候,就去执行我们传入的函数,并且把遍历出来的数字传给我们的函数,filter中的回调函数有一个要求:必须返回一个Boolean值,当返回true时,函数内部会自动将这次回调传入的值加入到新的数组中,当返回false时,函数内部会过滤掉这次传入的值

const nums = [10, 20, 111, 222, 444, 40, 50]
let newNums = nums.filter(function(n){
    return n < 100
})

高级函数map()的使用:

map()也需要传入一个回调函数,map()传入的函数的返回值作为另一个数组的新的值加入到新的数组中

const nums = [10, 20, 111, 222, 444, 40, 50]
let newNums = nums.filter(function(n){
    return n < 100
})
let new2Nums = newNums.map(function(n){
    return n * 2
})

高级函数reduce()的使用:需要出入一个回调函数,回调函数中需要传两个值,一个是前一个值(previousVlaue)和当前遍历的值,这里的previousValue是上一次遍历的值

reduce还有一个重载函数,该重载函数第一个为回调函数,第二个为初始化值

作用:对数组中所有的内容进行汇总

codewhy_vue笔记01_第75张图片

const nums = [10, 20, 111, 222, 444, 40, 50]
let newNums = nums.filter(function(n){
    return n < 100
})
let new2Nums = newNums.map(function(n){
    return n * 2
})

// 对new2Nums求和
// 上一次输出的结果:即new2Nums = [20, 40, 80, 100]
// 使用reduce()函数,使用第二个重载函数
// 第一次: preValue 0(自定义初始化值为0),n 20
// 第二次: preValue 20  n 40
// 第三次: preValue 60  n 80
// 第四次: preValue 140 n 100
let total = new2Nums.reduce(function(preValue, n){
    return preValue + n
}, 0)

// 最终:total = 240

以上的需求使用更简洁的代码:

const nums = [10, 20, 111, 222, 444, 40, 50]
let total = nums.filter(function(n){
    return n < 100
}).map(function(n){
    return n * 2
}).reduce(function(preValue, n){
    return preValue + n
},0)

还可以使用更简洁的写法:lambda表达式

const nums = [10, 20, 111, 222, 444, 40, 50]
let total = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n)

上面的计算总价的计算属性可以写为:

computed: {
    totalPrice(){
        return this.books.reduce(function(preValue, book){
            return preValue + book.price * book.count
        }, 0)
    }
}

2.1、v-model

v-model:表单绑定,表单双向绑定

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <input type="text" v-model="message">
  {{message}}
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

现在vue data中的数据和表单中的数据就进行了双向绑定,即message中的数据会自动填充到表单中,并且只要data或是输入框中的数据发生了变化,另外一方的数据也会同步(及双向绑定)。

image-20210707223205965

以前的mastche是响应式的,即只有vue中的数据变了,才会显示到前端,而前端的数据变了并不会影响到后端。

双向绑定的原理:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  
  <input type="text" :value="message">
  
  <input type="text" :value="message" @:input="valueChange">
  {{message}}
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      valueChange(event){
        this.message = event.target.value
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第76张图片

简化写法:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  
  <input type="text" :value="message">
  
  <input type="text" :value="message" @:input="message = $event.target.vlaue">
  {{message}}
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      valueChange(event){
        this.message = event.target.value
      }
    }
  })
script>
body>
html>

2.2、v-model和radio的结合使用

当存在多个单选框时:可以使用v-model直接绑定一个radio中的值到vue的data中

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <label for="male">
    <input type="radio" id="male" name="sex" value="" v-model="sex">
  label>
  <label for="female"><input type="radio" id="female" name="sex" value="" v-model="sex">
  label>
  <h3>你选择的性别是:{{sex}}h3>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      // 给定一个默认值
      sex: '女'
    }
  })
script>
body>
html>

效果:

codewhy_vue笔记01_第77张图片

2.3、复选框checkbox

v-model实现单个多选框:一般是跟一个Boolean值绑定

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <label for="agree">
    <input type="checkbox" id="agree" v-model="isAgree">同意协议
  label>
  <h4>你选择的是:{{isAgree}}h4>
  <button :disabled="!isAgree">下一步button>

div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      isAgree: false
    }
  })
script>
body>
html>

v-model绑定到一个Boolean值是,当点击时该布尔值会执行取反操作

codewhy_vue笔记01_第78张图片

当多选框有多个时:一般是跟一个数组绑定,当用户选择了某个多选框时,v-model绑定的数组就会把该多选框对应的value的值加入到数组中,取消选中时,v-model又会自动移除该值

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <input type="checkbox" value="篮球" v-model="hobbies">篮球
  <input type="checkbox" value="台球" v-model="hobbies">台球
  <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
  <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
  <input type="checkbox" value="足球" v-model="hobbies">足球

  <h4>你的爱好是:{{hobbies}}h4>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      hobbies: []
    }
  })
script>
body>
html>

codewhy_vue笔记01_第79张图片

select(下拉框):也分为选择一个多个的情况

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <select name="test" id="" v-model="fruit">
    <option value="苹果">苹果option>
    <option value="香蕉">香蕉option>
    <option value="">option>
    <option value="西瓜">西瓜option>
    <option value="李子">李子option>
  select>
  <h4>你选择的水果是:{{fruit}}h4>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      // 设置默选中
      fruit: '李子'
    }
  })
script>
body>
html>

选择单个:

codewhy_vue笔记01_第80张图片

选择多个:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <select name="test" id="" v-model="fruit">
    <option value="苹果">苹果option>
    <option value="香蕉">香蕉option>
    <option value="">option>
    <option value="西瓜">西瓜option>
    <option value="李子">李子option>
  select>
  <h4>你选择的水果是:{{fruit}}h4>

  
  <select name="test2" id="t2" v-model="fruits" multiple>
    <option value="苹果">苹果option>
    <option value="香蕉">香蕉option>
    <option value="">option>
    <option value="西瓜">西瓜option>
    <option value="李子">李子option>
  select>
  <h4>你选择的水果是:{{fruits}}h4>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      // 设置默选中
      fruit: '李子',
      fruits: []
    }
  })
script>
body>
html>

可以按住ctl键选择多个

codewhy_vue笔记01_第81张图片

2.4、input中的值绑定

我们之前input中的值都是通过value属性绑定的,我们也可以将input中的值在vue的data中预先写好,然后再从vue中取出到前端显示

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <label :for="item" v-for="(item, index) in originHobbies">
    <input type="checkbox" :value="item" v-model="hobbies" :id="item">{{item}}
  label>
  <h4>你的选择是:{{hobbies}}h4>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      originHobbies: ['篮球', '足球', '排球', '乒乓球', '高尔夫球', '台球'],
      hobbies: []
    }
  })
script>
body>
html>

codewhy_vue笔记01_第82张图片

2.5、v-model修饰符的使用

1、lazy修饰符

lazy:懒加载

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <input type="text" v-model.lazy="message">{{message}}
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

number修饰符:

input输入的东西都会被认为是字符类型,所以使用numer把数字字符转换为数字类型

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <input type="text" v-model.lazy="message">{{message}}

  
  <br>
  <input type="number" v-model.number="age">
  <h4>{{age}}--{{typeof(age)}}h4>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      age: 0
    }
  })
script>
body>
html>

image-20210708135813138

trim修饰符:去除字符串两端空格

虽然浏览器显示时会帮我们自动去除空格,但后端存储的字符串中左右两端的空格还是存在的。

codewhy_vue笔记01_第83张图片

使用trim后

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <input type="text" v-model.lazy="message">{{message}}

  
  <br>
  <input type="number" v-model.number="age">
  <h4>{{age}}--{{typeof(age)}}h4>

  
  <br>
  <input type="text" v-model.trim="content">
  <h3>输入为:{{content}}h3>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      age: 0,
      content: ''
    }
  })
script>
body>
html>

空格已被去除

codewhy_vue笔记01_第84张图片

三、组件化开发

codewhy_vue笔记01_第85张图片

注册组件的基本步骤:

  • 创建组件构造器
  • 注册组件
  • 使用组件

codewhy_vue笔记01_第86张图片

codewhy_vue笔记01_第87张图片

3.1、vue组件的基本使用

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <h3>我是标题h3>
  <p>我是内容,哈哈哈哈哈哈哈哈哈哈哈哈p>
  <p>我是内容,呵呵呵呵呵呵呵呵呵呵呵p>
div>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

codewhy_vue笔记01_第88张图片

上面的内容如果要显示多次,就可以把它抽象为一个组件

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <my-cpn>my-cpn>
  
  <my-cpn>my-cpn>
  <my-cpn>my-cpn>
  <my-cpn>my-cpn>
div>
<script src="../js/vue.js">script>
<script>
  // 1.创建组件构造器对象
  const cpnC = Vue.extend({
    // ES6的新语法: ``包含的字符串可以换行
    template: `
          

我是标题

我是内容,哈哈哈哈哈哈哈哈哈哈哈哈

我是内容,呵呵呵呵呵呵呵呵呵呵呵

`
}) // 2.注册组件:Vue.component('组件的标签名', 组件的构造器对象) Vue.component('my-cpn', cpnC) const app = new Vue({ el: '#app', data: { message: '你好呀' } })
script> body> html>

codewhy_vue笔记01_第89张图片

codewhy_vue笔记01_第90张图片

codewhy_vue笔记01_第91张图片

codewhy_vue笔记01_第92张图片

3.2、全局组件和局部组件

以下方式注册的组件为全局组件:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <my-cpn>my-cpn>
div>
<script src="../js/vue.js">script>
<script>
  const cpnC = Vue.extend({
    template: `
      

我是标题

我是内容,哈哈哈

`
}) Vue.component('my-cpn', cpnC) const app = new Vue({ el: '#app', data: { message: '你好呀' } })
script> body> html>

全局组件:意味着可以同时再多个vue实列下使用,如下,再创建一个vue实列挂载app2:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <my-cpn>my-cpn>
div>


<div id="app2">
  <my-cpn>my-cpn>
div>
<script src="../js/vue.js">script>
<script>
  const cpnC = Vue.extend({
    template: `
      

我是标题

我是内容,哈哈哈

`
}) Vue.component('my-cpn', cpnC) const app = new Vue({ el: '#app', data: { message: '你好呀' } }) const app2 = new Vue({ el: '#app2' })
script> body> html>

codewhy_vue笔记01_第93张图片

怎么注册的组件才是局部组件:在特定的vue下注册的组件是局部组件:

在Vue实列中使用components注册组件

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <cpn>cpn>
div>


<div id="app2">
  
  <cpn>cpn>
div>
<script src="../js/vue.js">script>
<script>
  const cpnC = Vue.extend({
    template: `
      

我是标题

我是内容,哈哈哈

`
}) Vue.component('my-cpn', cpnC) const app = new Vue({ el: '#app', data: { message: '你好呀' }, components: { cpn: cpnC } }) const app2 = new Vue({ el: '#app2' })
script> body> html>

可以发现:cpn在app2的vue实列中不能使用了

codewhy_vue笔记01_第94张图片

3.3、父组件和子组件

注册组件的方式:

  • 全局组件注册: Vue.componet(组件名,组件构造器)
  • 局部组件注册:在vue是实列中,使用components{组件名:组件构造器}
  • 在组件构造器中使用components注册,这样的好处是可以在组件构造器中模板中该组件注册器中注册过的组件

这里使用第三种方式

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn2>cpn2>
div>
<script src="../js/vue.js">script>
<script>
  // 1.创建第一个组件(子组件)
  const cpnC1 = Vue.extend({
    template: `
      

我是标题

我是内容,哈哈哈

`
}) // 2.创建第二个组件构建器(父组件) const cpnC2 = Vue.extend({ template: `

我是标题

我是内容,呵呵呵

`
, // 在组件构造器2中注册组件构造器1 components: { cpn1: cpnC1 } }) const app = new Vue({ el: '#app', data: { message: '你好呀' }, // 这里的组件构造器2中注册了组件构造器1,然后组件构造器2在这里注册,就能保证两个组件构造器都被注册了 components: { cpn2: cpnC2 } })
script> body> html>

一般认为vue实列也是一个组件

注意:在vue挂载的html下,直接使用在组件构造器中注册的组件是不能被识别的:如下就会报错:

<div id="app">
  <cpn2>cpn2>
  <cpn1>cpn1>
div>

codewhy_vue笔记01_第95张图片

如果要是用的话,可以在vue的实列中再注册一次:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn2>cpn2>
  <cpn1>cpn1>
div>
<script src="../js/vue.js">script>
<script>
  // 1.创建第一个组件(子组件)
  const cpnC1 = Vue.extend({
    template: `
      

我是标题

我是内容,哈哈哈

`
}) // 2.创建第二个组件构建器(父组件) const cpnC2 = Vue.extend({ template: `

我是标题

我是内容,呵呵呵

`
, // 在组件构造器2中注册组件构造器1 components: { cpn1: cpnC1 } }) const app = new Vue({ el: '#app', data: { message: '你好呀' }, // 这里的组件构造器2中注册了组件构造器1,然后组件构造器2在这里注册,就能保证两个组件构造器都被注册了 components: { cpn2: cpnC2, cpn1: cpnC1 } })
script> body> html>

3.4、注册组件的语法糖

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn1>cpn1>
  <cpn2>cpn2>
div>
<script src="../js/vue.js">script>
<script>
   /*语法糖方式注册:注意内部还是调用extend函数
  语法糖注册全局组件*/
  Vue.component('cpn1',{
    template: `
      

我是标题

我是内容

`
}) const app = new Vue({ el: '#app', data: { message: '你好呀' }, // 语法糖注册局部组件 components: { 'cpn2': { template: `

我是标题

我是内容

`
} } })
script> body> html>

也可以写为:key可以加单引号也可以不加

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn1>cpn1>
  <cpn2>cpn2>
div>
<script src="../js/vue.js">script>
<script>
   /*语法糖方式注册:注意内部还是调用extend函数
  语法糖注册全局组件*/
  Vue.component('cpn1',{
    template: `
      

我是标题

我是内容

`
}) const app = new Vue({ el: '#app', data: { message: '你好呀' }, // 语法糖注册局部组件 components: { cpn2: { template: `

我是标题

我是内容

`
} } })
script> body> html>

语法糖优点:省去了调用extend的步骤

codewhy_vue笔记01_第96张图片

组件模板的简单分离写法:

1、分离写法一

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
div>


<script type="text/x-template" id="cpn">
<div>
  <h3>我是标题</h3>
  <p>我是内容</p>
</div>
script>
<script src="../js/vue.js">script>
<script>
  // 使用分离写法注册全局组件,通过script的id获得template内容
  Vue.component('cpn', {
    template: '#cpn'
  })
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

codewhy_vue笔记01_第97张图片

分离写法2:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
div>


<template id="cpn">
  <div>
    <h3>我是标题h3>
    <p>我是内容p>
  div>
template>
<script src="../js/vue.js">script>
<script>
  Vue.component('cpn', {
    template: '#cpn'
  })
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

组件可以访问vue中的数据码?

组件内部是不能直接访问vue实列中的数据的。

codewhy_vue笔记01_第98张图片

结论:组件中也有自己的data属性,但data不能是一个对象,只能以一个函数。而且这个函数返回一个对象,对象内部保存着数据。

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
div>


<template id="cpn">
  <div>
    <h3>{{title}}h3>
    <p>我是内容p>
  div>
template>
<script src="../js/vue.js">script>
<script>
  Vue.component('cpn', {
    template: '#cpn',
    data(){
      return{
        title: '我是标题'
      }
    }
  })
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

codewhy_vue笔记01_第99张图片

vue组件中的data为什么必须是一个组件:

需求:把之前的计数器案例封装为一个组件

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <cpn>cpn>
  <cpn>cpn>
  <cpn>cpn>
div>

<template id="cpn">
  <div>
    <h3>当前计数:{{counter}}h3>
    <button @click="increment">+button>
    <button @click="decrement">-button>
  div>
template>
<script src="../js/vue.js">script>
<script>
  // 注册组件
  Vue.component('cpn', {
    template: '#cpn',
    data(){
      return{
        counter: 0
      }
    },
    methods: {
      increment(){
        this.counter++
      },
      decrement(){
        this.counter--
      }
    }
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    }
  })
script>
body>
html>

各个组件的counter并不会相互影响:这也是组件中的data必须返回一个函数的原因,因为每个函数都是返回一个对象,每个对象在内存空间中的地址是互不相同的。

codewhy_vue笔记01_第100张图片

3.5、父子组件的通信

codewhy_vue笔记01_第101张图片

codewhy_vue笔记01_第102张图片

codewhy_vue笔记01_第103张图片

下面的代码中,把vue实列看作父组件,组件看作子组件

props:使用数组传递数据:[]数组中单引号中的字符就是在使用该组件时的属性,通过v-bind绑定这个属性就可以把这个值绑定到vue实列中的变量

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <cpn v-bind:cmovies="movies" :cmessage="message">cpn>
div>

<template id="cpn">
  <div>
    <p>{{cmovies}}p>
    <p>{{cmessage}}p>
  div>
template>
<script src="../js/vue.js">script>
<script>
  // 定义模板对象:在vue中注册实列:
  // components{
  //  cpn: {对象}
  // }
  //下面定义的对象就是vue实列中要注册的对象
  const cpn = {
    template: '#cpn',
    // 可以使用数组形式传递数据
    props: ['cmovies', 'cmessage']
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      movies: ['海王', '海贼王', '海尔兄弟']
    },
    // 注册组件:使用属性增强写法
    components: {
      cpn
    }
  })
script>
body>
html>

注意:在使用组件时必须使用v-bind,如果不使用的话,vue会直接把双引号中的字符穿个组件props数组中的变量。

codewhy_vue笔记01_第104张图片

错误使用如下:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <cpn cmovies="movies" cmessage="message">cpn>
div>

<template id="cpn">
  <div>
    <p>{{cmovies}}p>
    <p>{{cmessage}}p>
  div>
template>
<script src="../js/vue.js">script>
<script>
  // 定义模板对象:在vue中注册实列:
  // components{
  //  cpn: {对象}
  // }
  //下面定义的对象就是vue实列中要注册的对象
  const cpn = {
    template: '#cpn',
    // 可以使用数组形式传递数据
    props: ['cmovies', 'cmessage']
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      movies: ['海王', '海贼王', '海尔兄弟']
    },
    // 注册组件:使用属性增强写法
    components: {
      cpn
    }
  })
script>
body>
html>

codewhy_vue笔记01_第105张图片

使用数组的话:[]中放的是字符,而我们又把它当作变量使用,不符合习惯。

传递方式二:props中使用对象(好处:可以指定类型)

props: {
    //类型限制
    cmovies: Array,
    cmessage: String
}

还可以提供默认值:默认值在父组件没有传递值的时候显示

props: {
    cmovies: Array,
    cmessage: {
        type: String,
        default: 'hello',
        // required为true时要求使用的时候必须传值
        required: true
    }
}

类型是数组或对象时默认值需要使用工厂函数返回

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <cpn :cmessage="message">cpn>
div>

<template id="cpn">
  <div>
    <p>{{cmovies}}p>
    <p>{{cmessage}}p>
  div>
template>
<script src="../js/vue.js">script>
<script>
  // 定义模板对象:在vue中注册实列:
  // components{
  //  cpn: {对象}
  // }
  //下面定义的对象就是vue实列中要注册的对象
  const cpn = {
    template: '#cpn',
    // 可以使用数组形式传递数据
    props: {
      cmovies: {
        type: Array,
        default(){
          return []
        }
      },
      cmessage: {
        type: String,
        default: 'hello',
        required: true
      }
    }
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      movies: ['海王', '海贼王', '海尔兄弟']
    },
    // 注册组件:使用属性增强写法
    components: {
      cpn
    }
  })
script>
body>
html>

codewhy_vue笔记01_第106张图片

其他写法:

codewhy_vue笔记01_第107张图片

codewhy_vue笔记01_第108张图片

注意:目前的vue中v-bind不支持驼峰命名,因此在有v-bind的地方,驼峰命名需要转换为-连接的形式

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn :cinfo="info">cpn>
div>

<template id="cpn">
  <div>{{cinfo}}div>
template>
<script src="../js/vue.js">script>
<script>
  const cpn = {
    template: '#cpn',
    props: {
      cinfo: {
        type: Object,
        default(){
          return {}
        }
      }
    }
  }
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      info: {
        name: 'why',
        age: 18,
        height: 188
      }
    },
    components: {
      cpn
    }
  })
script>
body>
html>

codewhy_vue笔记01_第109张图片

有驼峰命名时:

转化例子:myChildrenMessage 转换为 my-children-message

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn :c-info="info">cpn>
div>

<template id="cpn">
  <div>{{cInfo}}div>
template>
<script src="../js/vue.js">script>
<script>
  const cpn = {
    template: '#cpn',
    props: {
      cInfo: {
        type: Object,
        default(){
          return {}
        }
      }
    }
  }
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      info: {
        name: 'why',
        age: 18,
        height: 188
      }
    },
    components: {
      cpn
    }
  })
script>
body>
html>

父子间的通信:子传父

子组件通过$emit(‘要发送的事件名’,传递的参数)发送事件,父组件通过使用子组件时,监听子组件发送的事件获取子组件发来的数据:(注意子组件中不要使用驼峰命名),在脚手架中可以使用驼峰命名

父组件监听语法:@子组件发送的事件名=“父组件中的处理函数”

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <cpn @item-click="cpnClick">cpn>
div>

<template id="cpn">
  <div>
    <button v-for="item in categories" @click="btnClick(item)">{{item.name}}button>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const cpn = {
    template: '#cpn',
    data(){
      return{
        categories: [
          {id: 'aaa', name: '热门推荐'},
          {id: 'bbb', name: '手机数码'}
        ]
      }
    },
    methods: {
      btnClick(item){
        // 把我们点击了谁传递给父组件:$emit('要发送的事件名',传递的参数)
        this.$emit('item-click', item)
        console.log(item);
      }
    }
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn
    },
    methods: {
      cpnClick(item){
        console.log("父组件", item);
        console.log("conClick")
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第110张图片

3.6、知识回顾

计算属性

  • 计算属性的本质:get,set
  • 计算属性和methods的对比
    • 使用多次时,计算属性只调用一次,methods调用多次
    • 计算属性有缓存

事件监听

  • 事件监听的基本使用
  • 参数问题

修饰符

  • stop
  • prevent
  • .enter
  • .once
  • .native

条件判断

  • v-if/v-else-if/v-else
  • 登录小案例
  • v-show

循环遍历

  • 数组遍历

  • 对象遍历

  • 数组的那些方法是响应式的

  • 作业完成

书籍案例

v-model的基本使用

  • v-model的基本使用
  • v-model和radio/checkbox/select

v-model的修饰符

  • lazy
  • number
  • trim

组件化开发

  • 认识组件
  • 组件的基本使用
  • 全局组件和局部组件
  • 父组件和子组件
  • 组件注册的语法糖
  • 模板的分类写法
    • script
    • template

组件数据的存放

  • 子组件不能直接访问父组件
  • 子组件中有自己的data,而且必须是一个函数
  • 为什么必须是一个函数

父子组件的通信

  • 父传子:props
  • 子传父:$emit

codewhy_vue笔记01_第111张图片

3.7、父子组件通信-结合双向绑定案例

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn :number1="num1" :number2="num2">cpn>
div>
<template id="cpn">
  <div>
    <h4>props:{{number1}}h4>
    <input type="text" v-model="number1">
    <h4>props:{{number2}}h4>
    <input type="text" v-model="number2">
  div>
template>

<script src="../js/vue.js">script>
<script>

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      num1: 1,
      num2: 0
    },
    components: {
      cpn: {
        template: '#cpn',
        props: {
          number1: Number,
          number2: Number
        }
      }
    }
  })
script>
body>
html>

子组件中的props和input直接进行双向绑定,这是官方不推荐使用的方式,因为props中的数据是父组件传来的,它的值应该有父组件去改变,如果直接通过v-model直接修改,将会导致修改混乱,因此报错(虽然可以修改),官方推荐我们使用计算属性或者data去修改props中的值

codewhy_vue笔记01_第112张图片

正确的修改方法

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn :number1="num1" :number2="num2">cpn>
div>
<template id="cpn">
  <div>
    <h4>props:{{number1}}  data:{{dnumber1}}h4>
    <input type="text" v-model="dnumber1">
    <h4>props:{{number2}}  data:{{dnumber2}}h4>
    <input type="text" v-model="dnumber2">
  div>
template>

<script src="../js/vue.js">script>
<script>

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      num1: 1,
      num2: 0
    },
    components: {
      cpn: {
        template: '#cpn',
        props: {
          number1: Number,
          number2: Number
        },
        data(){
          return{
            dnumber1: this.number1,
            dnumber2: this.number2
          }
        }
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第113张图片

现在的需求:希望子组件中的输入框中的值改变的时候,父组件中的num1和num2也随着改变

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn :number1="num1" :number2="num2"
       @num1change="num1Change"
       @num2change="num2Change">cpn>
div>
<template id="cpn">
  <div>
    <h4>props:{{number1}}  data:{{dnumber1}}h4>
    
    
    <input type="text" :value="dnumber1" @input="num1Input">
    <h4>props:{{number2}}  data:{{dnumber2}}h4>
    <input type="text" :value="dnumber2" @input="num2Input" >
  div>
template>

<script src="../js/vue.js">script>
<script>

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      num1: 1,
      num2: 0
    },
    methods:{
      num1Change(value){
        // 因为value是子组件输入框传来的数据,默认是字符串,所以因该把它转换为int型
        // 转换方法一:使用*数字的方法: 如 this.num1 = value * 1
        // 方式二:使用parseInt方法
        this.num1 = parseInt(value)
      },
      num2Change(value){
        this.num2 = parseInt(value)
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        props: {
          number1: Number,
          number2: Number
        },
        data(){
          return{
            dnumber1: this.number1,
            dnumber2: this.number2
          }
        },
        methods: {
          num1Input(event){
            this.dnumber1 = event.target.value
            // 在值改变的同时,发送事件到父组件
            this.$emit('num1change', this.dnumber1)
          },
          num2Input(event){
            this.dnumber2 = event.target.value
            this.$emit('num2change', this.dnumber2)
          }
        }
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第114张图片

新的需求:让上面的data是下面data的1/100,下面data是上面data的100倍

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn :number1="num1" :number2="num2"
       @num1change="num1Change"
       @num2change="num2Change">cpn>
div>
<template id="cpn">
  <div>
    <h4>props:{{number1}}  data:{{dnumber1}}h4>
    
    
    <input type="text" :value="dnumber1" @input="num1Input">
    <h4>props:{{number2}}  data:{{dnumber2}}h4>
    <input type="text" :value="dnumber2" @input="num2Input" >
  div>
template>

<script src="../js/vue.js">script>
<script>

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      num1: 1,
      num2: 0
    },
    methods:{
      num1Change(value){
        // 因为value是子组件输入框传来的数据,默认是字符串,所以因该把它转换为int型
        // 转换方法一:使用*数字的方法: 如 this.num1 = value * 1
        // 方式二:使用parseInt方法
        this.num1 = parseFloat(value)
      },
      num2Change(value){
        this.num2 = parseFloat(value)
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        props: {
          number1: Number,
          number2: Number
        },
        data(){
          return{
            dnumber1: this.number1,
            dnumber2: this.number2
          }
        },
        methods: {
          num1Input(event){
            this.dnumber1 = event.target.value
            // 在值改变的同时,发送事件到父组件
            this.$emit('num1change', this.dnumber1)
            // 同时修改dnumber2的值
            this.dnumber2 = this.dnumber1 * 100
            // 同时让如组件的num2也改变
            this.$emit('num2change', this.dnumber2)
          },
          num2Input(event){
            this.dnumber2 = event.target.value
            this.$emit('num2change', this.dnumber2)
            this.dnumber1 = this.dnumber2 / 100
            // 同时让如组件的num2也改变
            this.$emit('num1change', this.dnumber1)
          }
        }
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第115张图片

案例逻辑整理:

codewhy_vue笔记01_第116张图片

3.8、父子组件的访问方式

codewhy_vue笔记01_第117张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
  
  <button @click="btnClick">点击button>
div>

<template id="cpn">
  <div>我是子组件div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      btnClick(){
        // 通过$children访问子组件
        console.log(this.$children);
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        methods: {
          showMessage(){
            console.log("showMessage");
          }
        }
      }
    }
  })
script>
body>
html>

可以发现this.$children拿到的是一个数组,并且这个数组中有一个VueComponent的vue组件,该组件可以看到我们定义的方法

于是我们通过该数组中的vue组件拿到刚才我们定义个函数

this.$children[0].showMessage()

拷贝三个组件:

<div id="app">
  <cpn>cpn>
  <cpn>cpn>
  <cpn>cpn>
  
  <button @click="btnClick">点击button>
div>

codewhy_vue笔记01_第118张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
  <cpn>cpn>
  <cpn>cpn>
  
  <button @click="btnClick">点击button>
div>

<template id="cpn">
  <div>我是子组件div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      btnClick(){
        // 通过$children访问子组件
        console.log(this.$children);
        // 拿到子组件中的方法
        this.$children[0].showMessage()
        // 去除name的name
        for(let c of this.$children){
          console.log(c.name);
          c.showMessage()
        }
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return{
            name: '我是子组件的name'
          }
        },
        methods: {
          showMessage(){
            console.log("showMessage");
          }
        }
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第119张图片

如果我们要拿到子组件中内容,一般不会使用 c h i l d r e n ( 如 果 以 后 的 代 码 修 改 了 , 通 过 下 标 闹 到 的 内 容 就 会 改 变 ) , 而 是 使 用 另 一 个 方 法 : children(如果以后的代码修改了,通过下标闹到的内容就会改变),而是使用另一个方法: children使refs

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn ref="a">cpn>
  <cpn ref="b">cpn>
  <cpn ref="c">cpn>
  
  <button @click="btnClick">点击button>
div>

<template id="cpn">
  <div>我是子组件div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    methods: {
      btnClick(){
        // 通过$children访问子组件
        console.log(this.$children);
        // 拿到子组件中的方法
        this.$children[0].showMessage()
        // 去除name的name
        for(let c of this.$children){
          console.log(c.name);
          c.showMessage()
        }

        // 通过ref拿到子组件对象
        console.log(this.$refs.a)
        // 拿到name属性
        console.log(this.$refs.a.name)
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return{
            name: '我是子组件的name'
          }
        },
        methods: {
          showMessage(){
            console.log("showMessage");
          }
        }
      }
    }
  })
script>
body>
html>

3.9、子访问父

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
div>

<template id="cpn">
  <div>
    <h4>我是子组件h4>
    <button @click="btnClick">按钮button>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn',
        methods: {
          // 1.访问父组件:$parent
          btnClick(){
            console.log(this.$parent);
          }
        }
      }
    }
  })
script>
body>
html>

打印出来是一个Vue,这是因为该子组件的父亲就是vue实列

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
div>

<template id="cpn">
  <div>我是cpn组件
    <ccpn>ccpn>
  div>
template>

<template id="ccpn">
  <div>
    <h4>我是子组件h4>
    <button @click="btnClick">按钮button>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return{
            name: '我是cpn组件的name'
          }
        },
        // 在嵌套一个子组件
        components: {
          ccpn: {
            template: '#ccpn',
            methods: {
              // 1.访问父组件:$parent
              btnClick(){
                console.log(this.$parent);
                // 拿到父组件的name
                console.log(this.$parent.name);
                // 访问根组件
                console.log(this.$root);
                // 访问根组件的message
                console.log(this.$root.message);
              }
            }
          }
        }
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第120张图片

四、插槽

4.1、插槽的基本使用

插槽:slot

需求不一样:

codewhy_vue笔记01_第121张图片

希望插槽具有扩展性

使用插槽:抽取共性,保留不同

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn><button>按钮button>cpn>
  <cpn><span>哈哈哈span>cpn>
  <cpn><i>呵呵呵i>cpn>
  <cpn><button>按钮button>cpn>
div>

<template id="cpn">
  <div>
    <h4>我是组件h4>
    <p>哈哈哈p>
    <slot>slot>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn'
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第122张图片

也可以给插槽一个默认值:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
  <cpn><span>哈哈哈span>cpn>
  <cpn><i>呵呵呵i>cpn>
  <cpn>cpn>
div>

<template id="cpn">
  <div>
    <h4>我是组件h4>
    <p>哈哈哈p>
    <slot><button>按钮button>slot>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn'
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第123张图片

如果一个插槽中插入多个值,则插槽会把所有的内容都插进去

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>
    <i>呵呵呵i>
    <span>哈哈哈span>
    <button>按钮button>
  cpn>
div>

<template id="cpn">
  <div>
    <h4>我是组件h4>
    <p>哈哈哈p>
    <slot><button>按钮button>slot>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn'
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第124张图片

4.2、具名插槽

指定位置插入:

image-20210708202802223

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn><span>标题span>cpn>
div>

<template id="cpn">
  <div>
    <slot><span>左边span>slot>
    <slot><span>中间span>slot>
    <slot><span>右边span>slot>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn'
      }
    }
  })
script>
body>
html>

这时vue会把所有的都替换掉,要解决这个问题,需要指定名字(具名)

codewhy_vue笔记01_第125张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn><span>标题span>cpn>
div>

<template id="cpn">
  <div>
    <slot name="left"><span>左边span>slot>
    <slot name="mid"><span>中间span>slot>
    <slot name="right"><span>右边span>slot>
    <slot>哈哈slot>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn'
      }
    }
  })
script>
body>
html>

这时只会替换没有名字的:

codewhy_vue笔记01_第126张图片

具名插槽的使用

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  
  <cpn><span slot="mid">标题span>cpn>
  <cpn><button slot="left">返回button>cpn>
div>

<template id="cpn">
  <div>
    <slot name="left"><span>左边span>slot>
    <slot name="mid"><span>中间span>slot>
    <slot name="right"><span>右边span>slot>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn'
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第127张图片

4.3、编译的作用域

组件和vue实列中各有一个isShow,其中实列中的isShow为true, 组件中的为false,我们在使用组件时,使用isShow,他用的是哪里的isShow?

使用的是vue实例中的isShow

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn v-show="isShow">cpn>
div>

<template id="cpn">
  <div>
    <h4>我是子组件h4>
    <p>哈哈哈p>
  div>
template>
<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀',
      isShow: true
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return{
            isShow: false
          }
        }
      }
    }
  })
script>
body>
html>

codewhy_vue笔记01_第128张图片

修改为false时:

codewhy_vue笔记01_第129张图片

通过实验发现,绑定的变量它只看他在那个模板下,刚才我们使用cpn组件是在vue实例下,所以他使用的是vue实例下的遍变量,它不管使用的是那个组件

4.4、作用域插槽

父组件替换插槽的标签,但是内容有子组件提供

codewhy_vue笔记01_第130张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
div>

<template id="cpn">
  <div>
    <ul>
      <li v-for="item in pLanguages">{{item}}li>
    ul>
  div>
template>

<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return {
            pLanguages: ['javaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift']
          }
        }
      }
    }
  })
script>

body>
html>

默认展示效果

codewhy_vue笔记01_第131张图片

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
  <cpn>
    
    <template slot-scope="slot">
      <span v-for="item in slot.data">{{item}} - span>
    template>
  cpn>
  <cpn>
    
    <template slot-scope="slot">
      <span v-for="item in slot.data">{{item}} * span>
    template>
  cpn>
div>

<template id="cpn">
  <div>
    
    <slot :data="pLanguages">
      <ul>
        <li v-for="item in pLanguages">{{item}}li>
      ul>
    slot>
  div>
template>

<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return {
            pLanguages: ['javaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift']
          }
        }
      }
    }
  })
script>

body>
html>

codewhy_vue笔记01_第132张图片

去除尾部的-或*:

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
<div id="app">
  <cpn>cpn>
  <cpn>
    
    <template slot-scope="slot">
      <span>{{slot.data.join(' * ')}}span>
    template>
  cpn>
  <cpn>
    
    <template slot-scope="slot">
      <span>{{slot.data.join(' - ')}}span>
    template>
  cpn>
div>

<template id="cpn">
  <div>
    
    <slot :data="pLanguages">
      <ul>
        <li v-for="item in pLanguages">{{item}}li>
      ul>
    slot>
  div>
template>

<script src="../js/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好呀'
    },
    components: {
      cpn: {
        template: '#cpn',
        data(){
          return {
            pLanguages: ['javaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift']
          }
        }
      }
    }
  })
script>

body>
html>

image-20210708210304614

作用插槽:就是让父组件拿到子组件中的数据,并以自己希望的格式展示。

五、模块化开发

javascript

codewhy_vue笔记01_第133张图片

别人改了自己的变量,导致的问题:

示例项目结构

codewhy_vue笔记01_第134张图片

index.html

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>

<script src="main.js">script>
<script src="a.js">script>
<script src="b.js">script>
<script src="xm.js">script>
<script>script>
body>
html>

main.js:没有写内容

a.js

// 小明
var name = '小明'
var age = 20
function sum(num1, num2){
  return num1 + num2
}

var flag = true

if(flag){
  console.log(sum(12, 20))
}

b.js

// 小红
var name = '小红'
var flag = false
console.log(name)

xm.js

if(flag){
  console.log("小明是天才");
}

运行时发现:小明是天才没有输出,因为小明知道自己定义了一个flag变量,并且为true

codewhy_vue笔记01_第135张图片

5.1、前端模块化雏形和Commonjs

之前问题的解决方式之一:

使用匿名函数闭包解决

a.js

// 小明
(function(){
  var name = '小明'
  var age = 20
  function sum(num1, num2){
    return num1 + num2
  }

  var flag = true

  if(flag){
    console.log(sum(12, 20))
  }
})()

但这时又带了一个问题,我想在xm.js中使用flag和sum函数时,发现不能用了,即代码的复用性大打折扣。

解决方式二:模块化

index.html:一样

a.js

// 小明
// 导出后:moduleA就等价于obj,而moduleA属于全局变量
var moduleA = (function(){
  // 定义导出的对象
  var obj = {}
  var name = '小明'
  var age = 20
  function sum(num1, num2){
    return num1 + num2
  }

  var flag = true

  if(flag){
    console.log(sum(12, 20))
  }
  // 给obj动态加一个属性flag和一个函数sum
  obj.flag = flag;
  obj.sum = sum;
  // 导出
  return obj
})()

b.js

// 小红
var moduleB = (function(){
  var obj = {}
  var name = '小红'
  var flag = false
  console.log(name)
  obj.flag = flag

  return obj
})()

xm.js

if(moduleA.flag){
  console.log("小明是天才");
}

结果

codewhy_vue笔记01_第136张图片

这是之前常用的解决命名冲图的办法,现在几乎不这样做了,因为现在有很多别人写好的,规范的模块化开发框架规范,我们直接使用就可以了。

常见的模块化规范:

CommonJS,AMD,CMD,也有ES6的Modules

CommonJS只是一个规范,具体的实现有一个比较著名的:Node

了解CommonJs:以下的语法需要底层Node的支持

codewhy_vue笔记01_第137张图片

codewhy_vue笔记01_第138张图片

5.2、ES6的模块化实现

导出/导入: export/import

示例项目结构

codewhy_vue笔记01_第139张图片

index.html

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>


<script src="a.js" type="module">script>
<script src="b.js" type="module">script>
<script src="xm.js" type="module">script>
body>
html>

a.js

导出方式一:

var name = '小明'
var age = 18
var flag = true

function sum(num1, num2){
  return num1 + num2
}

if(flag){
  console.log(sum(10, 20));
}

// 导出flag和sum
// 导出一个对象:export{}
export{
  // es6的增强写法
  flag,sum
}

b.js

var name = '小红'
var age = 20
var flag = false

xm.js

import {flag, sum} from "./a.js"
if(flag){
  console.log("小明是天才");
}

codewhy_vue笔记01_第140张图片

导出方式二:a.js

var name = '小明'
var age = 18
var flag = true

function sum(num1, num2){
  return num1 + num2
}

if(flag){
  console.log(sum(10, 20));
}

// 导出flag和sum
// 导出一个对象:export{}
// 导出方式一
export{
  // es6的增强写法
  flag,sum
}

// 导出方式二
export var num1 = 1000
export var height = 188

// 导出函数或类
export function mul(num1, num2){
  return num1 * num2
}

// 导出类
export class Person{
  run(){
    console.log("在奔跑");
  }
}

// export default:导入时可以自己命名,在一个js文件中,export default只能有一个
const address = '北京市'
export default address

xm.js

import {flag, sum} from "./a.js"
import {num1, height}  from "./a.js";

if(flag){
  console.log("小明是天才");
}

console.log(num1, height)

// 导入类和函数
import {mul, Person} from './a.js'

console.log(mul(220, 30));

const p = new Person()
p.run()

// 导入default,可以自定义名字
import addr from './a.js'

console.log(addr);

codewhy_vue笔记01_第141张图片

同一全部导入:

import {flag, sum} from "./a.js"
import {num1, height}  from "./a.js";

if(flag){
  console.log("小明是天才");
}

console.log(num1, height)

// 导入类和函数
import {mul, Person} from './a.js'

console.log(mul(220, 30));

const p = new Person()
p.run()

// 导入default,可以自定义名字
import addr from './a.js'

console.log(addr);

// 同一全部导入
import * as ex from './a.js'

console.log(ex.sum(12, 13));

codewhy_vue笔记01_第142张图片

上面的代码属于ES6规范,es6规范,浏览器都做了支持。

六、Webpack

6.1、认识webpack

webpack是一个现代的JavaScript应用静态模块打包工具:模块和打包

你可能感兴趣的:(前端,html5,es6,webpack,vue.js)