精华内容
下载资源
问答
  • vue从入门到精通

    2019-03-28 14:59:49
    vue从入门到精通适合刚入职场的小白,也适合职场多年的前端高手,为您全方位打造
  • Vue 入门到精通对应代码,持续更新中,进度会比《Vue 入门到精通》快,内容包括与《Vue 入门到精通》相对应的所有代码部分,以及部分未提到的案例。
  • 该资源适合新接触Vue的人员进行学习,通过视频进行学习,更方便于理解。
  • Vue.js v3.0 教程Vue3 教程,vue.js从入门到精通vue.js3.0教程,零基础学习vue.js,Vue.js是一个专注于视图模型(ViewModal)的框架,轻巧、高性能、可组件化的MVVM库
  • vue.js视频教程从入门到精通,全套视频,好东西就要分享,祝愿所有的开发小伙伴能学东西。
  • vue入门到精通

    2017-11-10 21:43:08
    Vue.js (读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。...
  • vue.js从入门到精通

    2018-03-27 08:58:01
    vue.js从入门到精通,想要学习vue的可以下载看看,视频资源,真实可靠
  • 即是说这个框架可以用于简单复杂的各种场景 开发者:尤雨溪 Vue特点 1.采用组件化模式,提高代码复用率、且让代码更好维护 一个.vue文件就包括了html,css,js。编辑一个.vue文件,不会影响其他的.vue文件 2.声明式...

    01 Vue的基本概念

    • 概念

      • Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。即是说这个框架可以用于简单到复杂的各种场景
      • 开发者:尤雨溪
    • Vue特点

      1.采用组件化模式,提高代码复用率、且让代码更好维护
      一个.vue文件就包括了html,css,js。编辑一个.vue文件,不会影响其他的.vue文件
      2.声明式编码,让编码人员无需直接操作DOM,提高开发效率
      命令式编程就像“您如何做某事,而声明式编程更像您在做什么
      Vue实现:数据 – 虚拟DOM – 页面真实DOM

    • 搭建Vue开发环境

      https://cn.vuejs.org/v2/guide/installation.html

    • 容器和实例是一一对应的

      JS表达式是一种特殊的JS代码,特殊在表达式会生成一个值
      JS表达式: yige表达式会生成一个值,可以放在任何一个需要值的地方

      • a
      • a + b
      • demo(1)
      • x === y ? a : b

    {{XXX}}中,XXX是JS表达式,且XXX自动读取到该数据的所有属性
    一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新

    02 模板语法

    • 插值语法:
      • 功能:用于解析标签体内容
      • 写法:{{XXX}},xxx是js表达式,且可以直接读取到data中的所有属性
    • 指令语法:
      • 功能:用于解析标签(包括:标签属性、标签体内容、绑定事件···)
      • 举例:v-bind:href=“xxx” 或简写为 :href=“xxx”
      • PS:使用v-bind:后,会把值当成表达式进行处理。 v-bind : XXX 可以简写成 : XXX

    03 数据绑定

    • v-bind: 单向数据绑定
    • v-model:双向数据绑定,只能用于表单类(输入类元素,具有value值的元素)元素
      • v-model:value 可以简写成v-model

    04 el的两种写法

     - 在new Vue()对象中el直接赋值
     - 通过$mount()函数进行绑定
    
    • data的两种写法

    • 对象式:在new Vue()对象中data直接赋值

    • 函数式:

       例 :data : function() { return { name : 'XXX'} }
            data () { return { name : 'XXX'} }
      
    • PS :由Vue管理的函数,一定不要写成箭头函数,一旦写成了箭头函数,this就不再是Vue的实例了。

    05 MVVM模型

    M:模型(Model),对应data中的数据
    V:视图(View),模板
    VM:视图模型,Vue实例对象
    

    数据代理:通过一个对象代理对另一个对象中属性的操作
    Object.defineProperty(变量, 变量中的属性, {})
    例:

     let person = {
         name : 'xx',
         sex : 'boy'
     }
     Object.defineProperty(person, 'sex', {
         value : 18, 
         // 控制属性是否可以枚举,默认值false
         enumerable : true,
         // 控制属性是否可以被修改,默认值false
         writable : true, 
         // 控制属性是否可以被删除,默认值false
         configurable : true, 
         get(){},
         set(value){}
    })
    

    06 Vue中的数据代理

    a. 通过Vue实例来代理data对象中的属性操作
    b. 更加方便的操作data中的数据
    c. 通过Object.defineProperty()把data对象中所有属性添加到vm上。
       为每一个添加到vm上的属性,都指定一个getter/setter。
       在getter/setter内部去操作data中对应的属性。
    

    07 事件处理

    07_1. 事件的基本使用

    a. 可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

    <div id="example-2">
        <!-- `greet` 是在下面定义的方法名 -->
        <button v-on:click="greet">Greet</button>
    </div>
    var example2 = new Vue({
        el: '#example-2',
        data: {
            name: 'Vue.js'
        },
        // 在 `methods` 对象中定义方法
        methods: {
            greet: function (event) {
                alert(event.target)
            }
        }
    })
    

    b. 也可以用 JavaScript 直接调用方法

    example2.greet() // => 'Hello Vue.js!'
    

    c. 内联处理器中的方法
    v-on:click 可以写成 @click
    @click=“demo” 和 @click=“demo(event)” 效果一致,后者可以传参
    html代码:

    <div id="example-3">
        <button v-on:click="say('hi')">Say hi</button>
        <button v-on:click="say('what')">Say what</button>
    </div>
    

    javascript代码:

    new Vue({
        el: '#example-3',
        methods: {
            say: function (message) {
                alert(message)
            }
        }
    })
    

    d. 有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法

    <button v-on:click="warn('Form cannot be submitted yet.', $event)">
    	Submit
    </button>
    

    07_2. 事件修饰符

    • 在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。

    • 尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

    • 为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

      .stop
      .prevent
      .capture
      .self
      .once
      .passive

     <!-- 阻止单击事件继续传播 -->
     <a v-on:click.stop="doThis"></a>
    
     <!-- 提交事件不再重载页面 -->
     <form v-on:submit.prevent="onSubmit"></form>
    
     <!-- 修饰符可以串联 -->
     <a v-on:click.stop.prevent="doThat"></a>
    
     <!-- 只有修饰符 -->
     <form v-on:submit.prevent></form>
    
     <!-- 添加事件监听器时使用事件捕获模式 -->
     <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
     <div v-on:click.capture="doThis">...</div>
    
     <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
     <!-- 即事件不是从内部元素触发的 -->
     <div v-on:click.self="doThat">...</div>
    
            
    

    课间小插曲

    • @wheel:鼠标滚轮事件
    • @scroll:滚动条滚动事件

    07_3. 键盘事件

    (1). 在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

        .enter
        .tab (特殊,必须配合keydown使用)
        .delete (捕获“删除”和“退格”键)
        .esc
        .space
        .up
        .down
        .left
        .right
    

    (2). 系统修饰键:

    可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
    .ctrl
    .alt
    .shift
    .meta

    PS:

    • 系统修饰键配合keyup使用:按下修饰键的同事,再按下其他键,随后释放其他键,事件才被触发。系统修饰键配合keydown使用:正常触发事件
    • Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
    • Vue未提供别名的按键,可以使用按键原始的Key值去绑定,但注意要转为kebab-case(短横线命名)
    • keyCode 的事件用法已经被废弃了并可能不会被最新的浏览器支持
    • 在 Mac 系统键盘上,meta 对应 command 键 (⌘)。
      在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。
      在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。
      在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。
      在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。

    (3). .exact 修饰符

    .exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。

    <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
    <button v-on:click.ctrl="onClick">A</button>
    
    <!-- 有且只有 Ctrl 被按下的时候才触发 -->
    <button v-on:click.ctrl.exact="onCtrlClick">A</button>
    
    <!-- 没有任何系统修饰符被按下的时候才触发 -->
    <button v-on:click.exact="onClick">A</button>
    

    (4). 鼠标按钮修饰符:这些修饰符会限制处理函数仅响应特定的鼠标按钮

    .left
    .right
    .middle

    08. 计算属性: computed

    • 定义:要用的属性不存在,要通过已有属性计算得来
    • 原理:底层借助了Object.defineProperty方法提供的getter和setter。
    • get函数什么时候执行
      • 初次读取时会执行一次
      • 当依赖的数据发生改变时会被再次调用
    • 优势: 与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
    • 备注
      • 计算属性最终会出现在vm上,直接读取使用即可
      • 如果计算属性被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化

    例:

    <body>
      <div id="root">
          <h1> {{ name }} </h1>
          <h1> {{ name2 }} </h1>
          <h1> {{ fullName }} </h1>
      </div>
      <script type="text/javascript">
          Vue.config.productionTip = false; // 阻止 vue 在启动时生产生产提示
          // 创建Vue实例
          const x = new Vue({
              el: '#root',
              data: {
                  name: '张',
                  name2 : '三',
              },
              computed : {
                  // 完整形式
                  fullName : {
                      get() {
                          return this.name + '-' + this.name2
                      },
                      // set什么时候调用?当fullName被修改时
                      // 
                      set(value) {
                          const arr = value.split('-')
                          this.name = arr[0]
                          this.name2 = arr[1]
                      }
                  }
                  // 只读不写时,可以使用简写形式
                  fullName : {
                      // 实际上是使用的get函数
                      return this.name + '-' + this.name2
                  }
              }
          })
      </script>
    </body>
    

    课间小插曲:Vue 3 Snippets插件:提供代码片段,语法高亮和格式化的 VS Code 插件,能极大提高你的开发效率。

    09. 监视属性

    (1). 当监视属性发生变化时,回调函数自动调用,进行相关操作
    (2). 监视的属性必须存在,才能进行监视
    (3). 监视的两种写法
        a. new Vue时传入watch配置
        b. 通过vm.$watch进行监视
    

    例:

    <body>
      <div id="root">
          <h1>今天天气很{{info}}</h1>
          <button @click="changeWeather">切换天气</button>
      </div>
      <script type="text/javascript">
          Vue.config.productionTip = false; // 阻止 vue 在启动时生产生产提示
          // 创建Vue实例
          const x = new Vue({
              el: '#root',
              data: {
                  name: '张',
                  name2 : '三',
              },
              computed : {
                  info(){
                      return this.isHot ? '炎热' : '凉爽'
                  }
              },
              methods : {
                  changeWeather(event) {
                      this.isHot = !this.isHot
                  }
              },
              // 方式一
              watch : {
                  // 方式一正常写法
                  isHot : {
                      immediate : true, // 初始化时让handler调用一下
                      // 什么时候调用?当Hot发生改变的时候
                      handler(newValue, oldValue) {
                          consle.log('xxx')
                      }
                  },
                  // 方式一简写
                  isHot(newValue, oldValue){
                      consle.log('xxx')
                  },
              }
          })
    
          // 方式二正常写法
          x.$watch('isHot', {
              immediate : true,
              handler(newValue, oldValue) {
                  consle.log('xxx')
              }
          })
          // 方式二简写
          x.$watch('isHot', (newValue, oldValue) {
              consle.log('xxx')
          })
      </script>
    </body>
    

    深度监视

    • Vue中的watch默认不监测对象内部值的改变(一层)
    • 配置deep:true可以监测对象内部的改变(多层)
    • Vue自身可以监测内部值的改变,但Vue提供的watch默认不可以!
    • 使用watch时根据数据的具体结构,决定是否采用深度监视

    例:

    <body>
       <div id="root">
           <h3>a的值是{{info}}</h3>
           <button @click="numbers.a++">点我让a+1</button>
           <h3>b的值是{{info}}</h3>
           <button @click="numbers.b++">点我让b+1</button>
       </div>
       <script type="text/javascript">
           Vue.config.productionTip = false; // 阻止 vue 在启动时生产生产提示
           // 创建Vue实例
           const x = new Vue({
               el: '#root',
               data: {
                   numbers : {
                       a:1,
                       b:1
                   }
               },
               watch : {
                   // 监视多级结构中的某个属性的变化
                   /* 'numbers.a': {
                           handler(){
    
                           }
                       }, */
                   number:{
                       // 可以监测对象内部的改变
                       deep:true,
                       handler(){
                           
                       }
                   }
               }
           })
       </script>
    </body>
    

    总结

    watch和computed的对比

    • computed能完成的功能,watch都能完成
    • watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作

    两个重要的小原则

    • 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或者组件实例对象
    • 所有不被Vue管理的函数(定时器的回调函数、aja的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象

    10. Class与Style绑定

    • 10_1. 绑定class样式

      • 字符串写法:适用于class的类名不固定,需要动态生成
      • 数组写法:适用于要绑定的样式个数不确定,名字也不确定
      • 对象写法:适用于要绑定的样式个数确定、名字也确定,但动态决定要不要使用

      (1).绑定单个class

      html部分:

    <div :class="{'active':isActive}"></div>
    

    js部分:判断是否绑定一个active

    data() {
       return {
       isActive: true
       };
    }
    

    结果渲染为:

    <div class="active"></div>
    

    (2).若要绑定多个class,需要逗号隔开就行:(这里的activeTwo加不加引号都可以,也一样都能渲染,如下)

    <div class="activeOne" v-bind:class="{ activeTwo: isActive, 'activeThree': hasError }"></div>
    

    js部分:判断是否绑定对应class

    data() {
        return {
        isActive: true,
        hasError: true
        };
    }
    

    结果渲染为:

    <div class="activeOne activeTwo activeThree"></div>
    

    (3).数组语法

    <div :class="[activeClass, errorClass]"></div>
    
    data() {
       return {
        activeClass: "active",
        errorClass: "disActive"
        };
    },
    

    结果渲染为:

    <div class="active disActive"></div>
    

    (4). 绑定的对象

    <div :class="classObject"></div>
    
    data: {
        classObject: {
            active: true,
        }
    }
    
    • 10_2. 绑定style样式

      (1). 在 v-bind:style 直接设置样式:
    <div id="app">
           <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">XXX</div>
    </div>
    

    以上实例 div style 为:

    <div style="color: green; font-size: 30px;">XXX</div>
    

    (2). 也可以直接绑定到一个样式对象,让模板更清晰:

    <div id="app">
        <div v-bind:style="styleObject">XXX</div>
    </div>
    

    (3). v-bind:style 可以使用数组将多个样式对象应用到一个元素上:baseStyles, overridingStyles是样式对象

    <div id="app">
        <div v-bind:style="[baseStyles, overridingStyles]">XXX</div>
    </div>
    

    11. 条件渲染

    (1). v-if

    v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
    例:

    <h1 v-if="awesome">Vue is awesome!</h1>
    

    (2). v-else

    也可以用 v-else 添加一个“else 块”:
    例:

    <h1 v-if="awesome">Vue is awesome!</h1>
    <h1 v-else>Oh no 😢</h1>
    

    (3). v-else-if

    顾名思义,充当 v-if 的“else-if 块”,可以连续使用:
    例:

    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else-if="type === 'C'">C</div>
    <div v-else>Not A/B/C</div>
    

    PS: 类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

    (4). v-show

    用于根据条件展示元素的选项是 v-show 指令。用法大致一样:
    例:

    <h1 v-show="ok">Hello!</h1>
    

    不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。

    ps: v-show 不支持 元素,也不支持 v-else。

    (5). v-if vs v-show

    • v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
    • v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
    • 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
    • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
      较好;如果在运行时条件很少改变,则使用 v-if 较好。

    12. 列表渲染

    12_1. 基本用法

    • 我们可以用 v-for 指令基于一个数组来渲染一个列表。
    • v-for 指令需要使用 item in items 形式的特殊语法,
      • 其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。 index是当前项的索引
    <ul id="example-2">
        <li v-for="(item, index) in items">
            {{ parentMessage }} - {{ index }} - {{ item.message }}
        </li>
    </ul>
    var example2 = new Vue({
        el: '#example-2',
        data: {
            parentMessage: 'Parent',
            items: [
            { message: 'Foo' },
            { message: 'Bar' }
            ]
        }
    })
    
       1. 用于展示列表数据
       2. 语法:v-for="(item, index) in xxx" :key="yyy"
       3. 可遍历:数组、对象、字符串(用得较少)、指定次数(用得较少)
    

    12_2. key的内部原理(react、vue的key有什么作用)

    A. 虚拟DOM中key的作用:

    • key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,

    • 随后Vue进行【新虚拟DOM】和【旧虚拟DOM】的差异比较,比较规则如下:

      B. 对比规则:

    • 旧虚拟DOM中找到了与新虚拟DOM相同的key

      • 若虚拟DOM中内容没变,直接使用之前的真实DOM
      • 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    • 旧虚拟DOM中未找到与新虚拟DOM相同的key

      • 创建新的真实DOM,随后渲染到页面

    C. 用index作为key可能会引发的问题

    • 若对数据进行:逆序添加、逆序删除等破坏顺序操作时:
      • 会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低
    • 如果结构中还包含输入类的DOM:
      • 会产生错误DOM更新 ==> 界面有问题

    D. 开发中如何选择key?

    • 最好使用每条数据的唯一标识作为key, 比如:id、手机号、身份证号、学号等唯一标识

    • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的

      12_3. 列表过滤

      12_4. 列表排序

    展开全文
  • Vue学习从入门到精通(一)

    万次阅读 多人点赞 2018-08-08 18:54:32
      最近公司由于业务拓展,需要进行小程序相关的开发,本着朝全栈开发者努力,决定学习下Vue,去年csdn送了一本《Vue.js权威指南》,那就这本书开始练起来吧。哟吼。 一,环境搭建 今天主要说一下如何...

      最近公司由于业务拓展,需要进行小程序相关的开发,本着朝全栈开发者努力,决定学习下Vue,去年csdn送了一本《Vue.js权威指南》,那就从这本书开始练起来吧。哟吼。
    ###一,环境搭建
    今天主要说一下如何搭建环境,以及如何运行。
    ####1,npm安装

    brew install npm
    

    如果brew没有安装的话,大家可以brew如何安装哦,这里就不再详细说明了。
    ####2,安装vue-cli
    vue-cli是用node编写的命令行工具,因此需要进行全局安装。

     npm install -g vue-cli
    

    注:node的版本为4.x,及5.x及以上
    安装完成后,查看版本

    vue -V
    

    ###二,创建并运行项目
    环境安装后,我们可以使用vue-cli命令快速创建一个webpack构建的项目

    vue init webpack helloworld
    

    我在当前目录创建了一个helloworld的项目。然后我执行

    cd helloworld//跳转到该目录
    

    执行下面的命令来安装依赖

    npm install
    

    我们会看到当前目录生成了很多的文件,其中我们主要是在src这个文件夹下进行相关的操作的。执行如下命令,启动项目

    npm run dev
    

    打开浏览器,输入http://localhost:8080可以看到系统默认生成的页面了。

    这里写图片描述
    本来是有一个Vue的图标的,被我给去掉了,方便后面的调试。
    ###三,Vue.js 权威指南的第一个demo
    一切准备就绪,接下来我们开始练习《Vue.js权威指南》这本书中的demo,在网上找了许久,也没有找到书中的源码,很是遗憾啊。第一个demo的代码保存为jk.vue
    我这边将第一个demo的代码如下:

    
    <template>
    	<div id = "didi-navigator">
    		<ul>
    			<li v-for="tab in tabs">
    				{{tab.text}}
    			</li>
    		</ul>
    	</div>
    </template>
    <script>
    export default {
    name:'HelloWorld',
    data(){
    	return {
       tabs:[
            {text: '巴士'},
    		{text: '快车'},
    		{text: '专车'},
    		{text:'顺风车'},
    		{text:'出租车'},
    		{text:'代驾'}
    		]
      }
    }
    }
    </script>
    
    
    

    大家可以看到我这里和书上不太一样,主要就是我这里app.js已经创建过了,所以我这边没有必要执行new Vue这些操作了,具体原因后续会详细说明。
    App.vue中代码如下:

    <template>
      <div id="app">
        <HelloWorld/>
      </div>
    </template>
    
    <script>
    import HelloWorld from './components/jk'
    
    export default {
      name: 'App',
      components: { HelloWorld }
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

    由于style还有学到,大家不要介意样式不好看啊。嘿嘿
    运行结果如下:这里写图片描述
    在这里插入图片描述
    更多优质文章,可以微信扫码关注:
    这里写图片描述

    展开全文
  • 30天从Vue入门到精通教程
  • vue从入门到精通.rar

    2021-03-30 15:48:08
    vue入门教程系列源码,小白级别入门教程,包含12个小结的源代码。
  • vue从入门到精通学习笔记

    千次阅读 2020-04-05 11:58:02
    了解Vue.js 认识Vue.js Vue是一个渐进式框架,什么渐进式? 渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验 响应式 vue的响应式 数据发生改变的时候,页面也跟着改变 可以直接在...

    了解Vue.js

    认识Vue.js

    • Vue是一个渐进式框架,什么渐进式?
      • 渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验
    • 响应式
      • vue的响应式
        • 数据发生改变的时候,页面也跟着改变
        • 可以直接在浏览器中的console下通过对象.属性 = 值(app.message = ‘hello’)来改变数据,体验vue的响应式
    • Vue的特点
      • 解耦视图和数据
      • 可复用的组件
      • 前端路由技术
      • 状态管理
      • 虚拟DOM

    Vue.js安装

    • CDN引入

      <!-- 开发环境版本,代码没有压缩,包含了有帮助的命令行警告 -->
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <!-- 生产环境版本,优化了尺寸和速度 -->
      <script src="https://cdn.jsdelivr.net/npm/vue"></script>
      
    • 下载和引用

      开发环境    https://vuejs.org/js/vue.js
      生产环境	https://vuejs.org/js/vue.min.js
      
    • npm安装

      npm install vue
      

    hello vue.js

    • 数据展示

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
      	<meta charset="UTF-8">
      	<meta name="viewport" content="width=device-width, initial-scale=1.0">
      	<title>Document</title>
      	<script src="./node_modules/vue/dist/vue.js"></script>
      </head>
      
      <body>
      	<div id="app">{{ message }}</div>
      	<script>
      		const app = new Vue({
      			el: '#app',
      			data() {
      				return {
      					message: 'hello vue.js'
      				}
      			}
      		})
      	</script>
      </body>
      
      </html>
      

      {{}}语法:叫Mustache(玛斯塔)语法,可以进行数据计算,字符串的拼接。

      优点:可以完全的达到页面与数据的分离

    • 列表展示(for循环,item是每项的值,index是每个项的索引)

      <div id="app">
      	<ul v-for = "item in message">
      		<li>{{ item }}</li>
      	</ul>
      </div>
      <script>
      	const app = new Vue({
      		el: '#app',
      		data() {
      			return {
      				message: ['少年的你','最好的我们','寻梦环游记','匆匆那年']
      			}
      		}
      	})
      </script>
      
    • vue案例—计数器

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
      	<meta charset="UTF-8">
      	<meta name="viewport" content="width=device-width, initial-scale=1.0">
      	<title>Document</title>
      </head>
      
      <body>
      	<div id="app">
      		<!-- 方法1 -->
      		<!-- <button v-on:click="counter++">+</button>
      		<span>{{ counter }}</span>
      		<button v-on:click="counter--">-</button> -->
      		<!-- 方法2 -->
      		<input type="button" v-on:click="add" value="+" />
      		<span>{{ counter }}</span>
      		<input type="button" v-on:click="sub" value="-">
      	</div>
      	<script src="./node_modules/vue/dist/vue.js"></script>
      	<script>
      		new Vue({
      			el: '#app',
      			data() {
      				return {
      					counter: 0
      				}
      			},
      			methods: {
      				add:function() {
      					console.log('add');
      					this.counter++
      				},
      				sub:function() {
      					console.log('sub');
      					this.counter--
      				}
      			}
      		})
      	</script>
      </body>
      
      </html>
      
    • MVVM

      • Model View Model View

      • 搜索网站

        维基百科:https://www.wikipedia.org/

      • 绑定view和model实现数据的双向绑定,你变我也变

      • 解释

        • View层
          • 视图层
          • 在前端开发过程中,通常就是DOM
          • 主要作用是给用户展示各种信息
        • Model层
          • 数据层
          • 数据层是我们固定的四数据,更多的来自服务器,从网络上请求下来的数据
          • 在我们计算过程中,就是从后面抽取过来的obj
        • ViewModel层
          • 视图模型层
          • 视图模型层是视图层(View层)和模型层(Model层)沟通的桥梁
          • 一方面实现了数据的绑定,将Model层的实时改变渲染到视图层上
          • 另一方面实现了DOM监听,当DOM发生事件时,可以监听到,并在对应情况下改变对应的数据

    创建vue实例传递的opactions

    1. el
      • 类型:string | HTMLElement
      • 作用:决定之后Vue实例会管理那个DOM
    2. data
      • 类型:Object | Function 在组件当中data必须是一个函数
      • 作用:Vue实例对应的数据对象
    3. methods
      • 类型:{[key:string]:Function} 函数名:函数体(function(){})
      • 作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中调用

    vue的生命周期

    生命周期:事务从诞生到消亡的过程。

    vue生命周期:创建前/后,载入前/后,更新前/后,销毁前/后。【重:面试会考】

    生命周期函数,是vue自定义的公共函数,不需要创建,直接使用就🆗。

    生命周期图

    在这里插入图片描述

    生命钩子函数

    什么是生命周期函数?

    比如:

    beforeMount: function() {
    }
    
    // 或者
    beforeMount() {
    }
    
    • Vue的所有生命周期函数都是自动绑定到this的上下文上。所以,使用箭头函数的话,this指向的父级作用域,就会报错。

    错误的形式:

    mounted:() => {
    }
    

    beforeCreate

    img

    在实例初始化之后,数据观测和暴露了一些有用的实例属性与方法。

    实例初始化——new Vue()

    数据观测——在vue的响应式系统中加入data对象中所有数据,这边涉及到vue的双向绑定,可以看官方文档上的这篇深度响应式原理 深度响应式原理

    暴露属性和方法——就是vue实例自带的一些属性和方法,我们可以看一个官网的例子,例子中带$的属性和方法就是vue实例自带的,可以和用户定义的区分开来

    var data = { a: 1 }
    var vm = new Vue({
      el: '#example',
      data: data
    })
    
    vm.$data === data // => true
    vm.$el === document.getElementById('example') // => true
    
    // $watch 是一个实例方法
    vm.$watch('a', function (newValue, oldValue) {
      // 这个回调将在 `vm.a` 改变后调用
    })
    复制代码
    

    created

    • el属性对生命周期的影响

    img

    // 有el属性的情况下
    new Vue({
    el: '#app',
    beforeCreate: function() {
      console.log('调用了beforeCreate')
    },
    created: function() {
      console.log('调用了created')
    },
    beforeMount: function() {
      console.log('调用了beforeMount')
    },
    mounted: function() {
      console.log('调用了mounted')
    }
    })
    
    // 输出结果
    // 调用了beforeCreate
    // 调用了created
    // 调用了beforeMount
    // 调用了mounted
    复制代码
    // 在没有el属性的情况下,没有vm.$mount
    
    new Vue({
    beforeCreate: function() {
      console.log('调用了beforeCreate')
    },
    created: function() {
      console.log('调用了created')
    },
    beforeMount: function() {
      console.log('调用了beforeMount')
    },
    mounted: function() {
      console.log('调用了mounted')
    }
    })
    
    // 输出结果
    // 调用了beforeCreate
    // 调用了created
    复制代码
    // 在没有el属性的情况下,但是有vm.$mount方法
    
    var vm = new Vue({
    beforeCreate: function() {
      console.log('调用了beforeCreate')
    },
    created: function() {
      console.log('调用了created')
    },
    beforeMount: function() {
      console.log('调用了beforeMount')
    },
    mounted: function() {
      console.log('调用了mounted')
    }
    })
    
    vm.$mount('#app')
    
    // 输出结果
    // 调用了beforeCreate
    // 调用了created
    // 调用了beforeMount
    // 调用了mounted
    
    • template属性对生命周期的影响

    img

    主要分三种情况:

    1. 在实例内部有template属性的时候,直接用内部的,然后调用render函数去渲染。
    2. 在实例内部没有找到template,就调用外部的html。实例内部的template属性比外部的优先级高。
    3. 要是前两者都不满足,那么就抛出错误。

    我们来看以下几个例子:

    new Vue({
      el: '#app',
      template: '<div id="app">hello world</div>'
    })
    
    //页面上渲染出了hello world
    复制代码
    <div id="app">hello world</div>
    
    new Vue({
      el: '#app'
    })
    
    // 页面上渲染出了hello world
    复制代码
    //两者都存在的时候
    
    <div id="app">hello world2</div>
    
    new Vue({
      el: '#app',
      template: '<div id="app">hello world1</div>'
    })
    // 页面上渲染出了hello world1
    

    从上述的例子可以看出内部的优先外部的。

    • 关于这个生命周期中的一些问题:

    1、为什么el属性的判断在template之前? 因为el是一个选择器,比如上述例子中我们用到的最多的是id选择器app,vue实例需要用这个el去template中寻找对应的。

    2、实际上,vue实例中还有一种render选项,我们可以从文档上看一下他的用法:

    new Vue({
      el: '#app',
      render() {
        return (...)
      }
    })
    

    3、上述三者的渲染优先级:render函数 > template属性 > 外部html

    4、vue编译过程——把tempalte编译成render函数的过程。

    beforeMount和mounted

    life-mounted.png

    <div id="app">
      <p>{{message}}</p>
    </div>
    
    new Vue({
      el: '#app',
      data: {
        message: 1
      },
      beforeMount: function() {
        console.log('调用了beforeMount');
        console.log(this.message)
        console.log(this.$el)
      },
      mounted: function() {
        console.log('调用了mounted');
        console.log(this.message)
        console.log(this.$el)
      }
    })
    
    // 输出的结果:
    // 调用了beforeMount
    // 1
    // <div>
    // </div>
    
    // 调用了mounted
    // 1
    // <div id="app">
    //  <p>1</p>
    // </div>
    

    创建vue实例的$el,然后用它替代el属性。

    beforeUpdate和updated

    img

    这个过程中,我们会发现,当一个数据发生改变时,你的视图也将随之改变,整个更新的过程是:数据改变——导致虚拟DOM的改变——调用这两个生命钩子去改变视图

    • 重点:这个数据只有和模版中的数据绑定了才会发生更新。
    // 没绑定的情况
    
    var vm = new Vue({
      el: '#app',
      template: '<div id="app"></div>',
      beforeUpdate: function() {
        console.log('调用了beforeUpdate')
      },
      updated: function() {
        console.log('调用了uodated')
      },
      data: {
        a: 1
      }
    })
    
    vm.a = 2
    //这种情况在控制台中是什么都不会输出的。
    复制代码
    var vm = new Vue({
      el: '#app',
      template: '<div id="app">{{a}}</div>',
      beforeUpdate: function() {
        console.log('调用了beforeUpdate')
      },
      updated: function() {
        console.log('调用了uodated')
      },
      data: {
        a: 1
      }
    })
    
    vm.a = 2
    
    // 输出结果:
    // 调用了beforeUpdate
    // 调用了uodated
    复制代码
    

    beforeDestory和destoryed

    img

    在beferoDestory生命钩子调用之前,所有实例都可以用,但是当调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

    不常用的生命钩子函数

    • activated:当组件激活的时候调用
    • deactivated:当组件停用的时候调用
    • errorCaptured:这个生命钩子可以看官网,2.5.0之后才有的。当捕获一个来自子组件的错误时被调用。

    let vm = new Vue({
      el: '#app',
      data: {
        message: 1
      },
      template: '<div id="app"><p>{{message}}</p></div>',
      beforeCreate() {
        console.log('调用了beforeCreate')
        console.log(this.message)
        console.log(this.$el)
      },
      created() {
        console.log('调用了created')
        console.log(this.message)
        console.log(this.$el)
      },
      beforeMount() {
        console.log('调用了beforeMount')
        console.log(this.message)
        console.log(this.$el)
      },
      mounted() {
        console.log('调用了mounted')
        console.log(this.message)
        console.log(this.$el)
      },
      beforeUpdate() {
        console.log('调用了beforeUpdate')
        console.log(this.message)
        console.log(this.$el)
      },
      updated() {
        console.log('调用了updated')
        console.log(this.message)
        console.log(this.$el)
      },
      beforeDestory() {
        console.log('调用了beforeDestory')
        console.log(this.message)
        console.log(this.$el)
      },
      destoryed() {
        console.log('调用了Destoryed')
        console.log(this.message)
        console.log(this.$el)
      }
    })
    
    vm.message = 2
    复制代码
    
    • 输出的结果:
    // 调用了beforeCreate
    // undefined
    // undefined
    // 调用了created
    // 1
    // undefined
    // 调用了beforeMount
    // 1
    // <div></div>
    // 调用了mounted
    // 1
    // <div id="app"><p>1</p></div>
    // 调用了beforeUpdate
    // 2
    // <div id="app"><p>2</p></div>
    // 调用了updated
    // 2
    // <div id="app"><p>2</p></div>
    

    代码规范:缩进,一般来说是缩进4个空格,但实际上缩进2个空格会更加的规范。

    Vue的基础语法

    模板语法

    插值操作( {{}} )

    • Mustach语法,也就是双大括号({{}})语法

      • mustach:胡子,胡须

        <div id="app">
        	<h2>{{ message }}</h2>
        </div>
        <script src="./node_modules/vue/dist/vue.js"></script>
        <script>
        	new Vue({
        		el: '#app',
        		data() {
        			return {
        				message: 'hello meustach'
        			}
        		}
        	})
        </script>
        
      • Mustach语法,可以进行数值的计算,数据的绑定,字符串的拼接

    常见指令 (v-xxx)

    v-once指令

    • 只显示第一次绑定的值,不会跟着用户的操作而改变

    • 元素和组件只渲染一次,不会跟着数据的改变而改变

    v-html指令

    • 绑定html标签
    <div id="app">
        <!-- 显示 点我  超链接   点击之后就跳转到https://pic.images.ac.cn/image/5e87056c7bec6网页 -->
    	<h2 v-html = "url"></h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    				url: `<a href = "https://pic.images.ac.cn/image/5e87056c7bec6">点我</a>`
    			}
    		}
    	})
    </script>
    

    v-text指令

    • 绑定文本值

      <div id="app">
      	<!-- 显示 hello v-text,good -->
      	<h2>{{ message }},good</h2>
      	<!-- 显示 hello v-text -->
      	<h2 v-text = "message">good</h2>
      </div>
      <script src="./node_modules/vue/dist/vue.js"></script>
      <script>
      	const app = new Vue({
      		el: '#app',
      		data() {
      			return {
      				message: 'hello v-text'
      			}
      		}
      	})
      </script>
      
    • 不灵活,只能绑定确定的值,不能进行数据拼接,添加拼接值后,拼接值会被v-text的值覆盖

    v-pre

    • 标签作用一样,写什么就展示什么

    • 用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法

      <div id="app">
      	<!-- 显示 hello v-text,good -->
      	<h2>{{ message }},good</h2>
      	<!-- 显示 {{ message }},good -->
      	<h2 v-pre>{{ message }},good</h2>
      </div>
      <script src="./node_modules/vue/dist/vue.js"></script>
      <script>
      	const app = new Vue({
      		el: '#app',
      		data() {
      			return {
      				message: 'hello v-text'
      			}
      		}
      	})
      </script>
      

    v-clock

    • 在某些情况下,我们浏览器可能会直接显示出未编译的Mustach标签

    • clock:斗篷

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
      	<meta charset="UTF-8">
      	<meta name="viewport" content="width=device-width, initial-scale=1.0">
      	<title>Document</title>
      	<style>
      		/* v-lock存在的时候不显示内容 */
      		[v-lock] {
      			display: none;
      		}
      	</style>
      </head>
      
      <body>
      
      	<div id="app" v-lock>
      		<!-- 显示 hello v-text,good -->
      		<h2>{{ message }},good</h2>
      		<!-- 显示 {{ message }},good -->
      		<h2 v-pre>{{ message }},good</h2>
      	</div>
      	<script src="./node_modules/vue/dist/vue.js"></script>
      	<script>
      		// 在vue解析之前,div中有一个属性v-clock
      		// vue解析完成后,div中没有v-lock属性
      		setTimeout(function () {
      			const app = new Vue({
      				el: '#app',
      				data() {
      					return {
      						message: 'hello v-text'
      					}
      				}
      			});
      		},1000);
      	</script>
      </body>
      
      </html>
      
    • 页面加载的时候起一个类似缓冲的作用

    绑定属性(v-bind)

    v-bind

    • 作用:动态绑定属性

    • 缩写: :

    • 预期:any(with argument) | Object(without argument)

    • 参数:attrOrProp(optional)

      
      <div id="app">
      	<!-- 通过图片地址,动态绑定元素属性,显示图片 -->
      	<!-- 图片不会显示 -->
      	<img src="imgUrl">
      	<!-- 图片会显示 -->
          <!-- v-bind的原型 --> 
      	<img v-bind:src="imgUrl" >
          <!-- v-bind的简写形式 -->   
      	<img :src="imgUrl" >
              
      	<!-- 通过 v-html 标签绑定形式,动态显示图片 -->
      	<div v-html="img"></div>
      </div>
      <script src="./node_modules/vue/dist/vue.js"></script>
      <script>
      	new Vue({
      		el: '#app',
      		data() {
      			return {
      				// 图片地址
      				imgUrl: 'http://imgs.aixifan.com/content/2016_07_10/1468158502.gif',
      				img: '<img src="http://imgs.aixifan.com/content/2016_07_10/1468158502.gif"/>'
      			}
      		}
      	})
      </script>
      
      

    v-bind的语法糖

    • 也就是v-bind的简写方式,在绑定属性之前,去掉v-bind,直接用v-bind的省略方式来绑定数据(v-bind:src -----》 :src)

    动态绑定对象

    class语法
    <!DOCTYPE html>
    <html lang="en">
    
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<title>Document</title>
    		<style>
    			.active{
    				color: red;
    			}
    		</style>
    	</head>
    
    	<body>
    		<div id="app">
    			<!-- 可以通过app.isactive来改变属性的值(布尔值),展示不同的状态 -->
    			<!-- <h2 :class="{key1:value1, key2:value2}">{{name}}</h2> -->
    			<!-- <h2 :class="{类名1:true, 类名2:boolean}">{{name}}</h2> -->
    			<!-- 元素绑定的class和动态绑定的class在浏览器中加载会合并 -->
    			<h2 class="title" :class="{active:isactive, line:isline}">{{name}}</h2>
    			
    			<!-- 简化写法:将绑定的class属性写成一个方法,然后绑定封装后的方法,让页面看起来更加的简洁 -->
    			<h2 class="title" :class="getClass()">{{name}}</h2>
    			<button type="button" v-on:click="check">按钮</button>
    		</div>
    		<script src="./node_modules/vue/dist/vue.js"></script>
    		<script type="text/javascript">
    			var app = new Vue({
    				el: '#app',
    				data() {
    					return {
    						name: '小陈',
    						isactive: true,
    						isline: true
    					}
    				},
    				methods: {
    					// 通过按钮点击事件来切换绑定数据的显示样式
    					check: function(){
    						this.isactive = !this.isactive;
    					},
    					getClass: function() {
    						return {active:this.isactive, line:this.isline}
    					}
    				}
    			})
    		</script>
    	</body>
    
    </html>
    
    
    数组语法
    <!DOCTYPE html>
    <html lang="en">
    
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<title>Document</title>
    		<style>
    			.active{
    				color: red;
    			}
    		</style>
    	</head>
    
    	<body>
    		<div id="app">
    			<!-- 通过数组语法绑定多个class-->
    			<!-- 绑定的class属性有单引号时,当字符串解析 -->
    			<!-- 在页面显示成	<h2 class="active line"></h2> -->
    			<h2 :class="['active', 'line']">{{ name }}</h2>
    			
    			<!-- 绑定的class属性没有单引号时,当变量解析 -->
    			<!-- 在页面显示成   <h2 class="aaa bbb"></h2> -->
    			<h2 :class="[active, line]">{{ name }}</h2>
    			
    			<!-- 在页面显示成   <h2 class="aaa bbb"></h2> -->
    			<h2 :class="getClass()">{{ name }}</h2>
    		</div>
    		<script src="./node_modules/vue/dist/vue.js"></script>
    		<script type="text/javascript">
    			var app = new Vue({
    				el: '#app',
    				data() {
    					return {
    						name: '小陈',
    						active: 'aaa',
    						line: 'bbb'
    					}
    				},
    				methods: {
    					getClass: function(){
    						// 在使用方法绑定时,绑定数组中的属性值一定要加上this
    						// 不加 this 就会显示active line is not defind
    						// return [active, line]
    						
    						return [this.active, this.line]
    					}
    				}
    			})
    		</script>
    	</body>
    
    </html>
    

    实例

    • 点击列表中的哪一项,哪一项的值就变成红色

      • 步骤
        • 创建html页面
        • 引入vue.js包
        • 添加作用域(
        • 实例化Vue({})
        • 添加挂载点(el)
        • 添加data属性及要操作的movie数组
        • 将data中movie数组中的数据渲染到页面上
        • 给li标签绑定class属性,属性的索引等于点击的li的索引
        • 添加点击事件,将绑定class属性的索引赋值给点击的索引
      <!DOCTYPE html>
      <html lang="en">
      
      	<head>
      		<meta charset="UTF-8">
      		<meta name="viewport" content="width=device-width, initial-scale=1.0">
      		<title>Document</title>
      		<style type="text/css">
      			ul li {
      				/* 鼠标移上去,添加小手样式 */
      				cursor: pointer;
      			}
      			/* 元素绑定的class样式 */
      			.active {
      				color: red;
      			}
      		</style>
      	</head>
      
      	<body>
      		<!-- 2 创建作用域 -->
      		<div id="app">
      			<ul>
      				<!--通过切换索引值改变class-->
      				<!-- 遍历显示在那个标签里面v-for循环就写在那个标签里面 -->
      				<li v-for='(item,index) in movie' @click="change(index)" :class='{ active:index === i }'>{{ item }}</li>       
      			</ul>
      		</div>
      		<!-- 1 引包 -->
      		<script src="./node_modules/vue/dist/vue.js"></script>
      		<script type="text/javascript">
      			// 3 实例化vue
      			var app = new Vue({
      				// 4 添加挂载点 el
      				el: '#app',
      				data() {
      					return {
      						// 页面加载的时候给第一个li标签添加样式
      						// 元素的索引从0开始
      						i: 0, 
      						// 页面显示的数组数据
      						movie: ['寻梦环游记', '肖申克的救赎', '摩登家庭', '老友记']
      					}
      				},
      				methods: {
      					// 元素标签点击事件
      					change: function(index) {
      						// console.log(index);
      						// 将添加class属性的索引变成用户点击的索引
      						this.i = index; 
      					}
      				}
      			})
      		</script>
      	</body>
      
      </html>
      

    v-bind绑定style样式

    • 在写css属性名的时候,我们可以采用
      • 驼峰命名法(fontSize)
      • 短横线分割法(‘font-size’)
    • 绑定class有两种语法
    对象语法
    <h2 :style="{fontSize: end + 'px'}">{{ message }}</h2>
    style后面跟的是一个对象类型
    对象的key是css属性名称
    对象的value是具体赋的值,值可以来自data中的属性
    
    <!DOCTYPE html>
    <html lang="zh">
    <head>
    	<meta charset="UTF-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<meta http-equiv="X-UA-Compatible" content="ie=edge">
    	<title></title>
    </head>
    <body>
    	<div id="app">
    		<!-- <h2 :style="{key: value}"></h2> -->
    		<!-- key是css的属性名   value是属性值 -->
    		<!-- 这样编译会报错,编译的时候浏览器把50px当成一个变量编译的,但是变量不能以数组开头 -->
    		<!-- <h2 :style="{font-size: 50px}">{{ message }}</h2> -->
    		<!-- 解决方法: 将 50px  变成  '50px' -->
    		<h2 :style="{'font-size': '50px'}">{{ message }}</h2>
    		<h2 :style="{fontSize: '50px'}">{{ message }}</h2>
    		
    		<!-- 直接引用变量finalSize -->
    		<!-- 引用的变量的值有单位,直接引用变量 -->
    		<h2 :style="{fontSize: finalSize, color: finalColor }">{{ message }}</h2>
    		<!-- 通过函数封装来改变样式 -->
    		<h2 :style="getStyle()">{{ message }}</h2>
    		<!-- 引用变量的值没有单位,在变量后面通过字符串的拼接来添加单位 -->
    		<h2 :style="{fontSize: end + 'px'}">{{ message }}</h2>
    	</div>
    	<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    	<script type="text/javascript">
    		new Vue({
    			el: '#app',
    			data() {
    				return {
    					message: 'HerayChen',
    					finalSize: '60px',
    					end: 60,
    					finalColor: 'red'
    				}
    			},
    			methods: {
    				getStyle: function() {
    					return {fontSize: this.finalSize, color: this.finalColor }
    				}
    			}
    		})
    	</script>
    </body>
    </html>
    
    数组语法
    <h2 v-bind:style="[fontColor,backgroundColor]">{{ message }}</h2>
    style后面跟的是一个数组类型
    多个值,分隔即可
    
    <!DOCTYPE html>
    <html lang="zh">
    <head>
    	<meta charset="UTF-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<meta http-equiv="X-UA-Compatible" content="ie=edge">
    	<title></title>
    	<style type="text/css">
    		
    	</style>
    </head>
    <body>
    	<div id="app">
    		<h2 :style="[fontColor]">{{ message }}</h2>
    	</div>
    	<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    	<script type="text/javascript">
    		new Vue({
    			el: '#app',
    			data() {
    				return {
    					message: 'HerayChen',
    					fontColor: {color: 'red'}
    				}
    			}
    		})
    	</script>
    </body>
    </html>
    

    计算属性(computed)

    计算属性的基本使用

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<meta http-equiv="X-UA-Compatible" content="ie=edge">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<!-- 通过mustach语法实现拼接 -->
    			<h2>{{ cname + ' ' + ename }}</h2>
    			<h2>{{ cname }} {{ ename }}</h2>
    			
    			<!-- 通过函数方法实现拼接 -->
    			<h2>{{ getFullName() }}</h2>
    			
    			<!-- 通过计算属性实现拼接 -->
    			<!-- 注意:计算属性,在写的时候是通过方法组合而成的,但是在使用的时候是当成属性使用的,直接通过属性名调用即可,不需要加双小括号 -->
    			<h2>{{ fullName }}</h2>
    		</div>
    		<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    			new Vue({
    				el: '#app',
    				data() {
    					return {
    						ename: 'HerayChen',
    						cname: '肖晨'
    					}
    				},
    				// computed 计算属性
    				computed: {
                        // fullName在这里是一个属性,不是一个函数
    					fullName: function() {
    						return this.cname + ' ' + this.ename;
    					}
    				},
    				methods: {
    					getFullName() {
    						return this.cname + ' ' + this.ename;
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    
    

    计算属性的复杂操作(通过for循环,计算总价格及es6 中的for-in方法)

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<meta http-equiv="X-UA-Compatible" content="ie=edge">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<h2>所有书的总价格为:{{ books[0].price + books[1].price + books[2].price + books[3].price }}</h2>
    			<h2>所有书的总价格为:{{ totalPrice }}</h2>
    			<h2>所有书的总价格为:{{ tprice }}</h2>
    		</div>
    		<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    			new Vue({
    				el: '#app',
    				data() {
    					return {
    						books: [{
    							id: 202001,
    							name: '月亮与六便士',
    							price: 50
    						}, {
    							id: 202002,
    							name: '独家的记忆',
    							price: 35
    						}, {
    							id: 202003,
    							name: '我在未来等你',
    							price: 25
    						}, {
    							id: 202004,
    							name: '爱',
    							price: 250
    						}]
    					}
    				},
    				computed: {
    					totalPrice: function() {
    						let result = 0;
    						for(let i = 0; i < this.books.length; i++){
    							result += this.books[i].price;
    						}
    						return result;
    					},
    					tprice: function() {
    						let result = 0;
    						// es6中的for循环
    						for (let i in this.books) {
    							result += this.books[i].price;
    						}
    						return result;
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    计算属性的setter和getter

    <!DOCTYPE html>
    <html lang="zh">
    <head>
    	<meta charset="UTF-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<meta http-equiv="X-UA-Compatible" content="ie=edge">
    	<title></title>
    </head>
    <body>
    	<div id="app">
    		<h2>{{ fullName }}</h2>
    	</div>
    	<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    	<script type="text/javascript">
    		new Vue({
    			el: '#app',
    			data() {
    				return {
    					cname: '肖晨',
    					ename: 'HerayChen'
    				}
    			},
    			computed: {
    				// fullName: function() {
    				// 	return this.cname + ' ' + this.ename;
    				// },
    				
    				// 计算属性一般没有set方法,只读属性
    				fullName: {
    					set: function(newName) {
    						// 只有值更改后才会调用set方法
    						// 要使用set方法,set方法一定是有参数的
    						// 通过空格截取修改后的值
    						const names = newName.split(' ');
    						// 前面的部分是cname
    						this.cname = names[0];
    						// 后面的部分是ename
    						this.ename = name[1];
    						
    					},
    					get: function() {
    						return this.cname + ' ' + this.ename;
    					}
    				}
    			}
    		})
    	</script>
    </body>
    </html>
    

    计算属性和methods的对比

    计算属性(computed)比methods性能更高,methods加载一次调用一次(每次都会重新计算一次),计算属性只调用一次(只计算一次)。

    <!DOCTYPE html>
    <html lang="zh">
    <head>
    	<meta charset="UTF-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<meta http-equiv="X-UA-Compatible" content="ie=edge">
    	<title></title>
    </head>
    <body>
    	<div id="app">
    		<!-- 直接拼接 -->
    		<!-- 一般不使用这种方法,语法过于繁琐 -->
    		<h2>{{ cname + ' ' + ename }}</h2>
    		<!-- 通过函数拼接 -->
    		<!-- 调用多次多次,页面加载一次调用一次 -->
    		<h2>{{ getFullName() }}</h2>
    		<!-- 通过计算属性拼接 -->
    		<!-- 调用多次 不管调用多少次,fullName只调用一次 -->
    		<h2>{{ fullName }}</h2>
    	</div>
    	<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    	<script type="text/javascript">
    		new Vue({
    			el: '#app',
    			data() {
    				return {
    					cname: '肖晨',
    					ename: 'HerayChen'
    				}
    			},
    			computed: {
    				fullName: function() {
    					return this.cname + ' ' + this.ename;
    				}
    			},
    			methods: {
    				getFullName: function() {
    					return this.cname + ' ' + this.ename;
    				}
    			}
    		})
    	</script>
    </body>
    </html>
    

    es6语法总结

    let和const

    var/let:变量,const:常量

    • let

      • 具有块级作用域
      • 在if,for中var,没有块级作用域,(解决作用域方法:使用闭包,使用ES6语法)
      • 使用闭包解决var中没有块级作用域的原理是,函数是一个作用域【在javascript中只有函数是有作用域的】
    • const

      • 将某个变量变成常量

      • 常量是固定值,不可以再次赋值

      • const可以保证数据的安全性

      • 在es6开发中优先使用const,只有需要改变某一个标识符的时候才使用let

        注意:
        1 常量不可以再次修改
        const name = 'herayChen';
        name = 'xiaochen0';	// 错误
        2  常量声明之后必须赋值
        const name;	//错误
        3 常量的含义是指向的对象不能修改,但是可以改变对象内部的属性
        const obj = {
            name: 'xiaochen',
            age: 20
        }
        obj.age = 18;  //正确
        

    对象字面量的增强写法

    在const obj = {}中,{}就是obj的字面量。

    • 属性的增强写法

      // 属性的增强写法
      const name = 'xiaochen';
      const age = 20;
      const sex = '女';
      
      // ES5中
      const obj = {
      	name: name,
      	age: age,
      	sex: sex
      }
      // ES6中
      const obj = {
      	name,
      	age,
      	sex
      }
      
    • 函数的增强写法

      // 函数的增强写法
      // ES5
      const obj = {
      	add: function() {
      		
      	},
      	reducte: function() {
      		
      	}
      }
      // ES6
      const obj = {
      	add() {
      		
      	},
      	reducte() {
      		
      	}
      }
      

      最近更新:typescript(microsoft),flow(facebook),angular(goole)【框架本身就使用的是typescript】

    事件监听(v-on)

    • 作用:绑定事件监听器
    • 缩写:@click
    • 预期:Function | Inline Statement | Object
    • 参数:event

    基本使用

    <div id="app">
    	<h2>{{ counter }}</h2>
    	<!-- 
    		v-bind的语法糖:
    		<h2 v-bind:title="">{{ counter }}</h2>
    		<h2 :title="">{{ counter }}</h2>
    	 -->
    	<!-- 直接操作数据 -->
    	<button type="button" @click="counter++">+</button>
    	<button type="button" @click="counter--">-</button>
    	<!-- 绑定函数,调用 -->
    	<button type="button" v-on:click="increment">+</button>
    	<!-- v-on中的语法糖:@click  -->
    	<button type="button" @click="decrement">-</button>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				counter: 0
    			}
    		},
    		methods: {
    			increment() {
    				this.counter++;
    			},
    			decrement() {
    				this.counter--;
    			}
    		}
    	})
    </script>
    

    v-on参数

    情况一:

    ​ 如果该方法不需要额外参数,那么方法后面的()可以省略,但是如果方法本身中有一个参数,那么则会默认event参数传递进去。

    情况二:

    ​ 如果需要同时传递某一个参数,同时需要event时,剋通过$event传入事件。

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<meta http-equiv="X-UA-Compatible" content="ie=edge">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<!-- 1.事件调用的方法没有参数 -->
    			<!-- @click="btnClick"  或者 @click="btnClick()" -->
    			<button @click="btn1Click">按钮1</button>
    			
    			<!-- 2.有一个参数 -->
    			<!-- 在事件定义时,写函数时省略了小括号,但是方法本身是需要一个参数的 -->
    			<!-- 打印输出123 -->
    			<button @click="btn2Click(num)">按钮2</button>
    			<!-- 没有传递参数函数的形参是undefined -->
    			<button @click="btn2Click()">按钮2.1</button>
    			<!-- 打印输出MouseEvent对象 -->
    			<!-- 在进行事件操作的时候浏览器会自动生成一个event对象 -->
    			<!-- v-on绑定函数需要传递新参,但是没有传递形参及小括号,就输出event对象 -->
    			<button @click="btn2Click">按钮2.2</button>
    			
    			<!-- 3.有一个及多个参数 -->
    			<!-- 在方法定义时,我们需要event对象,还需要其他参数 -->
    			<!-- event is not defined -->
    			<!-- 在这里浏览器解析的时候是把event当成一个变量来解析的 -->
    			<button @click="btn3Click(num, event)">按钮3</button>
    			<!-- 在调用方法的时候如何手动获取event对象 ,通过 $event -->
    			<button @click="btn3Click(num, $event)">按钮3.1</button>
    			
    			
    		</div> 
    		<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    			new Vue({
    				el: '#app',
    				data() {
    					return {
    						num: 123
    					}
    				},
    				methods: {
    					btn1Click() {
    						console.log("btnClick");
    					},
    					btn2Click(abc) {
    						console.log(abc);
    					},
    					btn3Click(abc, event) {
    						console.log(abc, event);
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    v-on修饰符

    <!-- 1 停止冒泡 -->
    <button @click.stop="doThis"></button>
    <!-- 2 阻止默认行为 -->
    <button @click.prevent="doThis"></button>
    <!-- 3 阻止默认行为,没有表达式 -->
    <button @click.stop></button>
    <!-- 4 串联修饰符 -->
    <button @click.stop.prevent="doThis"></button>
    <!-- 5 键修饰符,键别名 -->
    <button @click.enter="onEnter"></button>
    <!-- 6 键修饰符,键代码 -->
    <button @click.13="onEnter"></button>
    <!-- 7 点击只会触发一次 -->
    <button @click.once="doThis"></button>
    

    示例:

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<meta http-equiv="X-UA-Compatible" content="ie=edge">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<!-- 1 .stop阻止事件冒泡的使用 -->
    			<div @click="divClick">
    				<!-- 通过 stop阻止事件向上冒泡 -->
    				<button @click.stop="btnClick">按钮</button>
    			</div>
    			
    			<!-- 2 .prevent修饰符的使用 -->
    			<form action="baidu.com">
    				<!-- 通过prevent阻止表单的默认提交 -->
    				<input type="submit" value="提交" @click.prevent="submitClick"/>
    			</form>
    			
    			<!-- 3 监听键盘的键帽 -->
    			<input type="text" @keyup.enter="keyUp" />
    			
    			<!-- 4 once修饰符的使用 -->
    			<button type="button" @click.once="btn2Click">提交</button>
    			
    		</div>
    		<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    			new Vue({
    				el: '#app',
    				data() {
    					return {
    
    					}
    				},
    				methods: {
    					divClick() {
    						console.log('divClick');
    					},
    					btnClick() {
    						console.log('btnClick');
    					},
    					submitClick() {
    						// 自定义提交
    						console.log('submitClick');
    					},
    					keyUp() {
    						// 监听键帽,按下回车键后才打印
    						console.log('keyUp');
    					},
    					btn2Click() {
    						// 只提交一次
    						console.log('btn2Click');
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    条件判断

    v-if的使用

    <div id="app">
    	<!--false不显示,true显示 -->
    	<h2 v-if="isShow">good morning HerayChen</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				isShow: true
    			}
    		}
    	})
    </script>
    

    v-if和v-else的使用

    <div id="app">
    	<!-- v-if中的条件为true时,显示v-if里面的内容 -->
    	<!-- v-if中的条件为false时,显示v-else里面的内容 -->
    	<h2 v-if="isShow">{{ message }}</h2>
    	<h2 v-else>{{ now }}</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				message: 'good morning HerayChen',
    				now: 'good afternoon HerayChen',
    				isShow: false
    			}
    		}
    	})
    </script>
    

    v-if,v-else-if,v-else的使用

    层层判断

    <div id="app">
    	<!-- 1 直接在标签上使用 -->
    	<h2 v-if="score >= 90">优秀</h2>
    	<h2 v-else-if="score >= 80">良好</h2>
    	<h2 v-else-if="score >= 60">及格</h2>
    	<h2 v-else>继续加油呀!</h2>
    	
    	<!-- 2 通过计算属性来使用 -->
    	<h1> {{ result }}</h1>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				score: 90
    			}
    		},
    		computed: {
    			result() {
    				let showMessage = '';
    				if (this.score >= 90) {
    					showMessage = '优秀'
    				} else if (this.score >= 80) {
    					showMessage = '良好'
    				} else if (this.score >= 60) {
    					showMessage = '及格'
    				} else{
    					showMessage = '继续加油呀~'
    				}
    				return showMessage;
    			}
    		}
    	})
    </script>
    

    条件渲染案例(条件判断)

    选择不同的方式登录

    在此过程中遇到的小问题:

    • 如果我们在输入内容的情况下,切换了类型,我们会发现文字依然显示之前输入的内容
    • 但是按道理讲,我们应该切换到另外一个input元素中了
    • 在另外一个input元素中,我们并没有输入内容
    • 为什么会出现这个问题呢?

    问题解答:

    • 这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已存在的元素,而不是重新创建新的元素。
    • 在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了。

    解决方案:

    • 如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key
    • 并且需要保证key的不同
    <div id="app">
    	<span v-if="isUser">
    		<label for="userName">手机账号</label>
    		<!-- 给input标签添加key属性,防止在页面中输入了账号然后想切换登录方式,输入的数据没有清除 -->
    		<!-- 这种现象的原因是:vue的虚拟DOM , 元素内部的复用问题-->
    		<!-- 给input添加key属性,将key作为一个标识,决定能不能在其他地方进行使用 -->
    		<!-- 当不需要在其他地方使用时,key的值一定唯一 -->
    		<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="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				isUser: true
    			}
    		}
    	})
    </script>
    

    v-show

    <div id="app">
    	<!-- v-if条件为false是,包含v-if指令的元素,根本就不会存在DOM-->
    	<!-- 创建 删除... -->
    	<h2 v-if="isShow">{{ message }}</h2>
    	
    	<!-- v-show是通过使用display:none来实现的 -->
    	<!-- display:block   display:none -->
    	<h2 v-show="isShow">{{ message }}</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				message: '知识改变命运,学习成就未来',
    				isShow: true
    			}
    		}
    	})
    </script>
    

    v-if和v-show对比:

    • v-if和v-show都可以决定一个元素是否渲染
      • 选择
        • v-if条件为false时,压根不会有对应的元素在DOM中
        • v-show条件为fasle是,仅仅是将元素的display属性设置为none
        • 当需要频繁的切换显示隐藏之间切片很频繁时,使用v-show
        • 当只有一次切换时,通过使用v-if

    循环遍历

    v-for遍历数组

    <div id="app">
    	<!-- 在遍历过程中没有使用索引值 -->
    	<ul>
    		<li v-for="item in movies">{{ item }}</li>
    	</ul>
    	<!-- 在遍历过程中获取索引值 -->
    	<ul>
    		<li v-for="(item, index) in movies">{{ index+1 }}.{{ item }}</li>
    	</ul>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				movies: ['寻梦环游记', '肖申克的救赎', '爱的冒险', '冰雪奇缘']
    			}
    		}
    	})
    </script>
    
    

    v-for遍历对象

    <div id="app">
    	<ul>
    		<!-- 在遍历对象中  item是对象中的每个属性的值 value -->
    		<li v-for="item in movies">{{ item }}</li>
    	</ul>
    	
    	<ul>
    		<!-- key 属性名 -->
    		<!-- item 属性值 -->
    		<li v-for="(item,key) in movies">{{ key }}-{{ item }}</li>
    	</ul>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				movies:{
    					id: 1,
    					name: '动物世界',
    					actor: '李易峰',
    					time: '2018-05-04'
    				}
    			}
    		}
    	})
    </script>
    

    组件的key属性

    • 官方推荐使用v-for是,给对应的元素或者组件添加上一个key属性
    • 为什么要使用key属性呢?
      • 这个其实和Vue的Diff算法有关系
    • 当某一层有很多相同的节点时,也就是列表节点是,我们希望插入一个新的节点
      • 我们希望在b和c之间插入f,Diffy算法执行起来是这样的。
      • 即把D更新成C,E更新成D,最后再插入E,这样做效率不太高
    • 所以我们需要使用key来给每一个节点做一个唯一标识
      • Diff算法就可以正确的识别此节点
      • 找到正确的位置插入新的值
    • key的作用是为了高效的更新虚拟DOM


    数组中的响应式方法

    1 push()
    2 pop()
    3 shift()
    4 unshift()
    5 splice()
    6 sort()
    7 reverse()
    8 Vue中的set方法

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<meta http-equiv="X-UA-Compatible" content="ie=edge">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<ul>
    				<li v-for="item in letter" :key="item">{{ item }}</li>
    			</ul>
    			<button type="button" @click="btnClick">按钮</button>
    		</div>
    		<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    			new Vue({
    				el: '#app',
    				data() {
    					return {
    						letter: ['A', 'B', 'C', 'D', 'E'],
    						nums: [1, 3, 4, 77, 33, 6]
    					}
    				},
    				methods: {
    					btnClick() {
    						// 1 push()
    						// 在数组后添加一个元素
    						// Math.random().toString(36).substr(2) 随机生成字母和数字的组合
    						this.letter.push(Math.random().toString(36).substr(2));
    						// 一次添加多个元素
    						this.letter.push('aaa', 'bbb', 'ccc');
    
    						// 2 pop()
    						// 删除数组的最后一个元素
    						this.letter.pop();
    
    						// 3 shift()
    						// 删除数组的第一个元素
    						this.letter.shift();
    
    						// 4 unshift()
    						// 在数组最前面添加一个元素
    						this.letter.unshift(Math.random().toString(36).substr(2));
    
    						// 5 splice()
    						// splice方法可以删除元素/插入元素/替换元素
    						// 删除
    						this.letter.splice(1, 2);
    						// splice(1, 2);//从第一个元素开始,向后删除2个元素		显示ADE
    						// 如果没有传第二个参数就删除从起始位置后的所有元素
    
    						// 替换
    						// 显示AFGHI
    						// 从第一个元素开始,向后替换四个元素
    						this.letter.splice(1, 4, 'F', 'G', 'H', 'I');
    						
    						// 插入
    						// 显示ABCDFGHIE
    						// 在数组的第四个元素后添加'F', 'G', 'H', 'I'
    						this.letter.splice(4, 0, 'F', 'G', 'H', 'I');
    						
    						// 6 sort()
    						// 数组的排序
    						// 打印输出 [1, 3, 33, 4, 6, 77]
    						console.log(this.nums.sort());
    						
    						// 7 reverse()
    						// 翻转数组
    						// 显示EDCBA
    						this.letter.reverse();
    
    						// 8 Vue中的set方法
    						// set(要修改的对象, 索引值, 修改后的值)
    						// 显示 bbb B C D E 
    						Vue.set(this.letter, 0, 'bbbb')
    
    						// 注意:通过索引值,更改数组中的元素,这个不是响应式的
    						// this.letter[0] = 'bbb';
    
    						// 使用可变参数(...)的函数
    						// function add(...num) {
    						// 	// 打印输出[1, 2, 3, 4, 4, 5, 5]
    						// 	console.log(num);
    						// }
    						// add(1, 2, 3, 4, 4, 5, 5);
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    阶段案例(图书购物车)

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<meta http-equiv="X-UA-Compatible" content="ie=edge">
    		<title></title>
    		<style type="text/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: #7F7F7F;
    				color: #5c6b77;
    				font-weight: 600;
    			}
    		</style>
    	</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 v-for="value in item">{{ value }}</td> -->
    							<td>{{ item.id }}</td>
    							<td>{{ item.name }}</td>
    							<td>{{ item.data }}</td>
    							<!-- 1 使用toFixed直接保留小数 -->
    							<!-- <td>{{ '¥' + item.price.toFixed(2) }}</td> -->
    							<!-- 2 通过函数的封装调用保留小数 -->
    							<!-- <td>{{ getFinalPrice(item.price) }}</td> -->
    							<!-- 3 过滤器 -->
    							<td>{{ item.price | getFinalPrice }}</td>
    							<td>
    								<button type="button" @click="increment(index)">+</button>
    								{{ item.count }}
    								<button type="button" @click="decrement(index)" :disabled="item.count <= 1">-</button>
    							</td>
    							<td>
    								<button type="button" @click="removeHandel(index)">移出</button>
    							</td>
    						</tr>
    					</tbody>
    				</table>
    				<h2>总价格:{{ totalPrice | getFinalPrice }}</h2>
    			</div>
    			<div v-else>
    				<h2>购物车为空</h2>
    			</div>
    
    		</div>
    		<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    
    		</script>
    		<script type="text/javascript">
    			new Vue({
    				el: '#app',
    				data() {
    					return {
    						books: [{
    							id: 1,
    							name: '《算法导论》',
    							data: '2006-9',
    							price: 85.00,
    							count: 1
    						}, {
    							id: 2,
    							name: '《计算机概论》',
    							data: '2018-9',
    							price: 35.00,
    							count: 1
    						}, {
    							id: 3,
    							name: '《网络技术与基础》',
    							data: '2006-9',
    							price: 84.00,
    							count: 1
    						}, {
    							id: 4,
    							name: '《编程珠玑》',
    							data: '2008-9',
    							price: 39.00,
    							count: 1
    						}, {
    							id: 5,
    							name: '《代码大全》',
    							data: '2006-9',
    							price: 85.00,
    							count: 1
    						}]
    					}
    				},
    				computed: {
    					totalPrice() {
    						// 1 普通的for循环
    						// let total = 0;
    						// for (let i = 0; i < this.books.length; i++) {
    						// 	total += this.books[i].price * this.books[i].count;
    						// }
    						// return total;
    
    						// 2 es6中的for let in循环
    						// let total = 0;
    						// for (let i in this.books) {
    						// 	// console.log(i);  i是数组的索引
    						// 	total += this.books[i].price * this.books[i].count;
    						// }
    						// return total;
    
    						// 3 es6中拿到数组中每一项的索引值
    						// let total = 0;
    						// for (let item of this.books) {
    						// 	// item 是数组中每一项的值
    						// 	// console.log(s);
    						// 	total += item.price * item.count;
    						// }
    						// return total;
    
    						// 高阶函数reduce
    						return this.books.reduce(function(preVaule, book) {
    							return preVaule + book.price * book.count;
    						}, 0);
    					}
    				},
    				methods: {
    					// 保留小数  函数
    					// getFinalPrice(price) {
    					// 	return '¥' + price.toFixed(2)
    					// }
    
    					// 加法函数
    					increment(index) {
    						// console.log('increment',index);
    						this.books[index].count++
    					},
    					// 减法函数
    					decrement(index) {
    						// console.log('decrement',index);
    						this.books[index].count--
    					},
    					removeHandel(index) {
    						this.books.splice(index, 1)
    					}
    				},
    				// 过滤器
    				filters: {
    					getFinalPrice(price) {
    						return '¥' + price.toFixed(2)
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    高阶函数(filter,map,reduce)

    1. 去除所有小于100的数组
    2. 将所有小于100的数组转成: 全部乘以2
    3. 将所有new2Num的数字相加,得到最终的结果

    普通js实现:

    const num = [10, 20, 30, 40, 50, 200];
    // 创建一个空数组
    let newNum = [];
    // 1 通过for循环将所有小于100的数据,添加到新数组中
    for (let s of num) {
        if (s < 100) {
            newNum.push(s)
        }
    }
    // 创建一个空数组
    let new2Num = [];
    // 2 通过for循环遍历1中得到的小于100的数据,将1中的数组的每一项都乘以2
    for (let n of newNum) {
    	new2Num.push(n * 2);
    }
    console.log(new2Num);
    
    // 3 遍历2中得到的数组,将数组中每项值相加
    let total = 0;
    for (let n of new2Num) {
    	console.log(total += n);
    }
    

    通过高阶函数实现:

    const num = [10, 20, 30, 40, 50, 200];
    	// 高阶函数
    	// 1 过滤
    	// filter函数  必须返回一个布尔值
    	// 当函数返回true时,函数内部会自动将这次回调的n加入到新的数组中
    	// 当函数返回false时,函数内部会过滤掉不符合条件的n
    	let newNum = num.filter(function(n) {
    		// console.log(n); //filter函数会回调6次
    		return n < 100;
    	});
    	console.log(newNum); //打印输出[10, 20, 30, 40, 50]
    
    	// 2 map
    	let new2Num = newNum.map(function(n) {
    		return n * 2;
    	});
    	console.log(new2Num); //打印输出[20, 40, 60, 80, 100]
    
    	// 3 reduce
    	// 作用: 对数组中所有的值进行汇总
    	// preVaule 上一次遍历返回的值
    	// 第一次:preVaule: 0  n: 20
    	// 第二次: preVaule: 第一次返回的值  n: 40
    	let total = new2Num.reduce(function(preVaule, n) {
    		return preVaule + n;
    	}, 0);
    	console.log(total);	// 打印输出300
    

    简化高阶函数:

    const num = [10, 20, 30, 40, 50, 200];
    let total = num.filter(function(n) {
    	return n < 100;
    }).map(function() {
    	return n * 2;
    }).reduce(function(preVaule, n) {
    	return preVaule + n;
    }, 0);
    console.log(total);
    

    高阶函数和es6简化:

    let total = num.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
    console.log(total);
    

    v-mode(数据的双向绑定)

    • 表单控件在实际开发中是非常常见的,特别是对于用户信息的提交,需要大量的表单

    • Vue中使用v-model指令来实现表单元素和数据的双向绑定

      <div id="app">
      	<input type="text" v-model="message" />
      	<h2>{{ message }}</h2>
      	
      	<!-- v-model的实现原理 --><!-- v-on:input监听用户输入的事件 -->
      	<!-- 1 v-bind绑定value属性 -->
      	<!-- 2 v-on指令给当前元素绑定input事件 -->
      	<input type="text" :value="name" @input="valueChange"/>
      	<input type="text" :value="name" @input="name = $event.target.value"/>
      	<h2>{{ name }}</h2>
      </div>
      <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
      <script type="text/javascript">
      	new Vue({
      		el: '#app',
      		data() {
      			return {
      				message: 'hello xiaochen',
      				name: 'Heray'
      			}
      		},
      		methods: {
      			valueChange(event) {
      				this.name = event.target.value;
      			}
      		}
      	})
      </script>
      

    v-model:radio(单选框)

    <div id="app">
    	<label for="male">
    		<!-- 单选按钮只能选择一个  添加name属性 或者 v-model属性-->
    		<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>
    	<h2>你选择的性别是:{{ sex }}</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				// 给sex添加值,让页面加载的时候默认选中男
    				sex: '男'
    			}
    		}
    	})
    </script>
    

    v-model:checkbox(复选框【单个复选框,多个复选框】)

    <div id="app">
    	<!-- 1 checkbox单选框 -->
    	<label for="agreement">
    		<input type="checkbox" id="agreement" v-model="isAgreement" />同意协议
    	</label>
    	<h2>你的选择是: {{ isAgreement }}</h2>
    	<!-- 只有统一协议才能下一步,isAgreement为false时下一步按钮是禁用的状态 -->
    	<button type="button" :disabled="!isAgreement">下一步</button>
    	<hr />
    	<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">滑板
    	<h2>你的爱好是:{{ hobbies }}</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				// 单选框对应的是一个布尔值
    				isAgreement: false,
    				// 多选框对应的是一个数组
    				hobbies: []
    			}
    		}
    	})
    </script>
    

    v-model:select(一个,多个)

    <div id="app">
    	<!-- 1 选择一个 -->
    	<select name="selected" v-model="fruit">
    		<option value="苹果">苹果</option>
    		<option value="香蕉">香蕉</option>
    		<option value="梨子">梨子</option>
    		<option value="樱桃">樱桃</option>
    		<option value="草莓">草莓</option>
    		<option value="车厘子">车厘子</option>
    	</select>
    	<h2>你喜欢的水果是:{{ fruit }}</h2>
    	<hr />
    	<!-- 2 选择多个 -->
    	<select name="selected" v-model="fruits" multiple="multiple">
    		<option value="苹果">苹果</option>
    		<option value="香蕉">香蕉</option>
    		<option value="梨子">梨子</option>
    		<option value="樱桃">樱桃</option>
    		<option value="草莓">草莓</option>
    		<option value="车厘子">车厘子</option>
    	</select>
    	<h2>你喜欢的水果是:{{ fruits }}</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				fruit:'草莓',
    				fruits:[]
    			}
    		}
    	})
    </script>
    

    值绑定

    <div id="app">
    	<label  v-for="(item, index) in hobbies" :for="index">
    		<input type="checkbox"  :value="item" :id="index" v-model="hobbies">{{ item }}
    	</label>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				hobbies: ['街舞', 'rapper', '滑板', '拉丁']
    			}
    		}
    	})
    </script>
    

    修饰符

    lazy修饰符:

    • 默认情况下,v-model默认是在input时间中同步输入框的数据的
    • 一般来说,就是一旦有数据发生改变对应的data中的数据就会自动发生改变
    • lazy修饰符可以让数据在失去焦点或者回车时才会更新

    number修饰符:

    • 默认情况下,在输入框中无论我们输入的师叔祖还是字母,都会被当作字符串类型进行处理
    • 但如果我们希望处理的是数字类型,那么最好直接将内容当作数字处理
    • number修饰符可以让输入框中输入的内容自动转成数字类型

    trim修饰符:

    • 如果用户输入的内容首尾有跟多空格,通常我们希望去掉
    • trim修饰符可以过滤内容左右两边的空格
    <div id="app">
    	<!-- 1 lazy修饰符 -->
    	<!-- 在失去焦点和回车后更新绑定的数据 -->
    	姓名:<input type="text" v-model.lazy="name"/>
    	<h2>{{ name }}</h2>
    	
    	<!-- 2 number修饰符 -->
    	<!-- 不管怎么输入,都只显示number类型的数据 -->
    	<!-- <input type="number" v-model="age"/>输入的是数字,但是显示出来的数据是string类型的 -->
    	年龄:<input type="text" v-model.number="age"/>
    	<h2>{{ age }}-{{ typeof age }}</h2>
    	
    	<!-- 3 trim修饰符 -->
    	<!-- 去除输入内容的前后空格 -->
    	爱好:<input type="text" v-model.trim="hobby"/>
    	<h2>{{ hobby }}</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    				name: 'xiaochen',
    				age: 18,
    				hobby: ''
    			}
    		}
    	})
    </script>
    

    组件开发

    什么组件化?

    一个完成的页面分成很多个组件,每个组件都用于实现页面的一个功能块,每个组件又能进行细分

    Vue组件化思想

    • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用
    • 任何应用都会被抽象成一颗组件树
      • 数据结构:数组/栈/堆/树结构

    组件化思想的应用:

    1. 有了组件化的思想,我们在之后的开发中就要充分的利用它
    2. 尽可能的将页面拆分成一个个小的,可复用的组件
    3. 这样让我们的代码更加方便组织和管理,并且扩展性也更强

    注册组件的基本步骤

    组件的使用分成三个步骤:

    1. 创建组件构造器
    2. 注册组件
    3. 使用组件

    在这里插入图片描述

    <div id="app">
    	<!-- 3 使用组件 -->
    	<my-info></my-info>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 1 创建组件构造器对象
    	const cnp = Vue.extend({
    		// 自定义组件的模板
            template: `
    			<div>
    				<h2>标题</h2>
    				<p>内容</p>
    				<p>尾部</p>
    			</div>
    		`
    	})
    	<!-- // 2 注册组件 -->
        //Vue.component('注册组件的标签名',组件构造器名)
    	Vue.component('my-info',cnp)
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		}
    	})
    </script>
    

    全局组件和局部组件

    <div id="app">
    	<!-- 3 使用全局组件 -->
    	<my-info></my-info>
    	<!-- 使用局部组件 -->
    	<cpns></cpns>
    </div>
    <div id="app2">
    	<!-- 使用全局组件 -->
    	<my-info></my-info>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 1 创建组件构造器对象
    	const cnp = Vue.extend({
    		template: `
    			<div>
    				<h2>标题</h2>
    				<p>内容</p>
    				<p>尾部</p>
    			</div>
    		`
    	})
    	<!-- // 2 注册组件(全局组件,意味着可以在多个Vue的实力下面使用) -->
    	Vue.component('my-info',cnp)
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		<!-- 自定义局部组件,局部组件只能在挂载点范围之内使用 -->
    		components: {
    			<!-- cpns使用组件的标签名 -->
    			cpns: cnp
    		}
    	})
    	new Vue({
    		el:'#app2'
    	})
    </script>
    

    父组件和子组件

    <div id="app">
    	<!-- <dad></dad> -->
    	<brother></brother>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 第一个组件构造器
    	const dad = Vue.extend({
    		template: 
    		`
    			<div>
    				<h2>头部</h2>
    				<div>身体</div>
    				<div>脚部</div>
    			</div>
    		`
    	})
    	<!-- // 第二个组件构造器 -->
    	const brother = Vue.extend({
    		template: 
    		`
    			<div>
    				<h2>head</h2>
    				<div>body</div>
    				<div>foot</div>
    				<dad></dad>
    			</div>
    		`,
    		components: {
    			<!-- 在brother组件里面使用dad组件里面的内容 -->
    			<!-- 然后使用brother组件,就可以显示brother组件和dad组件的内容 -->
    			<!-- 要想使用组件必须注册组件 -->
    			<!-- 组件名:组件模板 -->
    			dad: dad
    		}
    	})
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		components: {
    			<!-- dad: dad, -->
    			brother: brother
    		}
    	})
    </script>
    

    注册组件的语法糖

    <div id="app">
    	<!-- 全局组件 -->
    	<daD></daD>
    	<!-- 局部组件 -->
    	<cpn2></cpn2>
    </div>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 注册全局组件
    	const dad = Vue.component('dad', {
    		template:
    		`
    			<div>
    				<h2>我是dad模板中全局组件的内容</h2>
    			</div>
    		`
    	});
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		components: {
    			<!-- 注册局部组件 -->
    			'cpn2': {
    				template:
    				 `
    				<div>
    					<h2>我是dad模板中局部组件的内容</h2>
    				</div>
    				`
    			}
    		}
    	});
    </script>      
    

    模板的分离写法

    模板的分离写法:

    <div id="app">
    	<!-- 全局组件 -->
    	<daD></daD>
    	<!-- 局部组件 -->
    	<cpn2></cpn2>
    </div>
    
    <!-- 1 通过script标签提取模板 -->
    <!-- 注意类型必须是:text/x-template -->
    <script type="text/x-template" id="dad">
    	<div>
    		<h2>我是dad模板中全局组件的内容</h2>
    	</div>
    </script>
    
    <!-- 2 通过template标签 -->
    <template id="cpn2">
    	<div>
    		<h2>我是dad模板中局部组件的内容</h2>
    	</div>
    </template>
    
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 注册全局组件
    	const dad = Vue.component('dad', {
    		// 通过id引用模板
    		template: `#dad`
    	});
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		components: {
    			<!-- 注册局部组件 -->
    			'cpn2': {
    				template:`#cpn2`
    			}
    		}
    	});
    </script>
    

    组件可以访问Vue实例数据

    • 组件是一个单独功能模块的封装:
      • 这个模块有属于自己的HTML模板,也应该有属性自己的数据data
    • 组件里面是不能访问vue实例里面的数据的。

    组件数据的存放:

    1. 组件对象也有一个data属性(也可以有methods等属性)
    2. 只是这个data属性必须是一个函数
    3. 而且这个函数返回一个对象,对象内部保存着数据
    <div id="app">
    	<!-- 全局组件 -->
    	<daD></daD>
    	<!-- 局部组件 -->
    	<cpn2></cpn2>
    </div>
    
    <!-- 1 通过script标签提取模板 -->
    <!-- 注意类型必须是:text/x-template -->
    <script type="text/x-template" id="dad">
    	<div>
    <h2>{{ message }}</h2>
    </div>
    </script>
    
    <!-- 2 通过template标签 -->
    <template id="cpn2">
    	<div>
    		<h2>{{ message }}</h2>
    	</div>
    </template>
    
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 注册全局组件
    	const dad = Vue.component('dad', {
    		// 通过id引用模板
    		template: `#dad`,
    		data() {
    			return {
    				message: '我是dad模板中全局组件的内容'
    			}
    		}
    	});
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		components: {
    			<!-- 注册局部组件 -->
    			'cpn2': {
    				template: `#cpn2`,
    				data() {
    					return {
    						message: '我是dad模板中局部组件的内容'
    					}
    				}
    			}
    		}
    	});
    </script>
    

    组件中的数据存放为什么是一个函数(面试可能会问)

    函数每次都会返回一个新的新的对象,产生不同的数据。

    对象每次都作用在一个属性上,一个改变所有的都改变({}可能会相互影响)。

    <div id="app">
    	<cpn></cpn>
    	<cpn></cpn>
    </div>
    <!-- 组件模板 -->
    <template id="cpn">
    	<div>
    		<h2>当前计数:{{ num }}</h2>
    		<button type="button" @click="increment">+</button>
    		<button type="button" @click="decrement">-</button>
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 1 注册组件
    	Vue.component('cpn', {
    		template: `#cpn`,
    		// data是一个函数,函数每次都会返回一个新的对象
    		// 这样同时使用一个组件,点击一个组件,就不会改变其他组件的值
    		
    		// 如果data {} 返回的是一个对象,每次作用的都是一个同养的对象,一个改变其他的都改变
    		// 使用{},会产生连锁反应
    		data() {
    			return {
    				num: 0
    			}
    		},
    		methods: {
    			increment() {
    				this.num++
    			},
    			decrement() {
    				this.num--
    			}
    		}
    	})
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		}
    	})
    </script>
    

    父子组件的通信

    通信:相互交流,数据传递。在大组件(父组件)获取所有的后台数据,然后在传递给小组件(子组件),渲染到页面。

    如何进行父子组件的通信?

    1. 通过props(是properties属性的缩写)向子组件中传递数据
    2. 通过自定义事件向父组件发送消息

    父传子props

    <div id="app">
    	<!-- 在父组件里面使用子组件 -->
    	<!-- 在页面中显示[ "速度与激情", "肖申克的救赎", "友情之上", "摩登少年" ]  和  hello -->
    	<cpn v-bind:cmovies="movies" :cmessage="message"></cpn>
    	
    	<!-- 在传值后,如果没有用v-bind,则会把绑定字段,当成字符串解析 -->
    	<!-- 在页面中显示movies message -->
    	<cpn cmovies="movies" cmessage="message"></cpn>
    </div>
    
    <template id="cpn">
    	<div>
    		<p>{{ cmovies }}</p>
    		<!-- 循环遍历父组件中传递过来的数据 -->
    		<ul>
    			<li v-for="item in cmovies">{{ item }}</li>
    		</ul>
    		<h2>{{ cmessage }}</h2>
    	</div>
    </template>
    
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 自定义组件
    	const cpn = {
    		template: `#cpn`,
    		// 父传子props
    		// 1 数组
    		props: ['cmovies','cmessage'],
    		// 2 对象
    		prpos: {
    			// 1 类型的限制
    			// cmovies: Array,
    			// cmessage: String
    			
    			// 2 提供一些默认值,以及必传值
    			cmessage: {
    				type: String,
    				// 没有传值提供的默认值
    				default: 'aa',
    				// 传值时cmessage是必须传的值
    				required: true
    			},
    			cmovies: {
    				type: Array,
    				// 类型是对象或者数组时,默认值必须是一个函数
    				default() {
    					return []
    				}
    			}
    		}
    	}
    	
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    				message: 'hello',
    				movies:['速度与激情', '肖申克的救赎', '友情之上', '摩登少年']
    			}
    		},
    		components: {
    			cpn
    		}
    	})
    </script>
    

    在这里插入图片描述

    props数据验证

    验证支持的数据类型:

    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol
    • 自定义数据类型
    Vue.component('my-component',{
        props: {
            //基础的类型检查(null,匹配任何数)
            propA: Number,
            //多个可能的类型
            propB: [String, Number],
            //必填的字符
            propC: {
                type: String,
                required: true
            },
            //带有默认值的数字
            propD: {
                type: Number,
                default: 100
            },
            // 带有默认值的对象
            propE: {
                type: Object,
                default() {
                    // 返回一个默认值
                    return { message:'hello' }
                }
            },
            // 自定义验证函数
            propF: {
                validator(value){
                    //这个值必须匹配下列字符中的一个
                    return ['success', 'warning', 'danger'].indexOf(value) !== -1
                }
            }
        }
    })
    

    自定义数据类型:

    function Person(firstName, lastName){
        this.firstName = firstName
        this.lastName = lastName
    }
    Vue.component('blog-post', {
        props: {
            // 自定义数据类型
            author: Person
        }
    })
    

    props中的驼峰标识

    在子组件中,props中的数据使用了驼峰命名,在父组件中使用必须去掉驼峰(遇到大写字母在前面加-分隔,然后将大写字母变成小写字母)

    <div id="app">
    	<!-- 子组件是在父组件中有使用的 -->
    	<!-- 在子组件上绑定(v-bind)父组件传递过来的数据 -->
    	<!-- v-bind不支持驼峰命名 -->
    	<!-- <cpn :cinfo = "info"></cpn> -->
    	
    	<!-- props中绑定的数据是cInfo,使用了驼峰必须 -->
    	<!-- 使用是必须将 cInfo  写成 c-info-->
    	<!-- 遇到大写字母在前面加-,然后将其变成小写使用 -->
    	<cpn :c-info = "info"></cpn>
    </div>
    <template id="cpn">
    	<!-- 子组件的模板中有很多个标签,必须有一个跟标签将其包裹 -->
    	<div>
    		<!-- 使用父组件中传递过来的数据 -->
    		<!-- <h2>{{ cinfo }}</h2> -->
    		
    		<!-- props中使用了驼峰 -->
    		<!-- 在页面中显示 { "name": "萧辰", "age": 18, "hobbie": [ "街舞", "吉他", "滑板" ] } -->
    		<h2>{{ cInfo }}</h2>
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 子组件
    	const cpn = {
    		template: `#cpn`,
    		props: {
    			// cinfo: {
    			cInfo: {	
    				type:Object,
    				default() {
    					return {
    						
    					}
    				}
    			}
    		}
    	};
    	// 父组件
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    				info: {
    					name: '萧辰',
    					age: 18,
    					hobbie: ['街舞', '吉他', '滑板']
    				}
    			}
    		},
    		components: {
    			cpn
    		}
    	})
    </script>
    

    子组件向父组件中传递数据(自定义事件)

    自定义事件的流程:

    1. 在子组件中,通过$emit()来触发时间
    2. 在父组件中,通过v-on来监听子组件事件
    <!-- 父组件模板 -->
    <div id="app">
    	<!-- 监听v-bind子组件发射出的时间 -->
    	<!-- 子组件监听子组件传递过来的事件时绑定的事件不能使用驼峰命名 -->
    	<!--  cpnClick(item) 写成 cpnClick这样也是可以的,从子组件传递过来的方法,会默认将参数也传递过来,就像event一样-->
    	<cpn @itemclick="cpnClick(item)"></cpn>
    </div>
    <!-- 子组件模板 -->
    <template id="cpn">
    	<div>
    		<button v-for="item in cartegories" @click="btnClick(item)">{{ item.name }}</button>
    	</div>
    </template>
    
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	// 子组件
    	const cpn = {
    		template: '#cpn',
    		data() {
    			return {
    				cartegories:[
    					{
    						id: 'a',
    						name: '热门推荐'
    					},
    					{
    						id: 'b',
    						name: '手机数码'
    					},{
    						id: 'c',
    						name: '家用家电'
    					},{
    						id: 'd',
    						name: '手机办公'
    					},{
    						id: 'e',
    						name: '精选服饰'
    					}
    				]
    			}
    		},
    		methods: {
    			btnClick(item) {
    				// 查看用户点击的信息
    				// console.log(item);
    				// 将用户点击的信息传到父组件中
    				// 向父组件中发射自定义事件事件,及传递的参数
    				this.$emit('itemclick', item)
    			}
    		}
    	}
    	// 父组件
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		components: {
    			cpn
    		},
    		methods: {
    			// 父组件事件
    			cpnClick(item) {
    				console.log(item);
    			}
    		}
    	})
    </script>
    

    在这里插入图片描述

    父子组件通信实例

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<meta http-equiv="X-UA-Compatible" content="ie=edge">
    		<title></title>
    	</head>
    	<body>
    		<div id="app">
    			<cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"></cpn>
    		</div>
    		<!-- 子组件模板 -->
    		<template id="cpn">
    			<div>
    				<h2>props1:{{ number1 }}</h2>
    				<h2>data:{{ cnumber1 }}</h2>
    				<!-- <input type="text" v-model="cnumber1"/> -->
    				<input type="text" :value="cnumber1" @input="num1Input" />
    				<h2>props2:{{ number2 }}</h2>
    				<h2>data:{{ cnumber2 }}</h2>
    				<!-- <input type="text" v-model="cnumber2"/> -->
    				<input type="text" :value="cnumber2" @input="num2Input" />
    			</div>
    		</template>
    		<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    			const app = new Vue({
    				el: '#app',
    				data() {
    					return {
    						num1: 1,
    						num2: 0
    					}
    				},
    				methods: {
    					num1change(value) {
    						this.num1 = parseInt(value);
    					},
    					num2change(value) {
    						this.num2 = parseInt(value);
    					}
    				},
    				components: {
    					cpn: {
    						template: `#cpn`,
    						props: {
    							number1: Number,
    							number2: Number
    						},
    						data() {
    							return {
    								cnumber1: this.number1,
    								cnumber2: this.number2
    							}
    						},
    						methods: {
    							num1Input(event) {
    								// 1 将input中的value赋值到cnumber1
    								this.cnumber1 = event.target.value;
    
    								// 2 为了让父组件可以修改值,发出一个事件
    								this.$emit('num1change', this.cnumber1);
    
    								// 3 同时修改cnumber2的值
    								this.cnumber2 = this.cnumber1 * 100;
    								this.$emit('num2change', this.cnumber2)
    							},
    							num2Input(event) {
    								this.cnumber2 = event.target.value;
    								this.$emit('num2change', this.cnumber2);
    
    								// 3 同时修改cnumber2的值
    								this.cnumber1 = this.cnumber2 / 100;
    								this.$emit('num1change', this.cnumber1)
    							}
    						}
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    

    在这里插入图片描述

    父子组件的访问方式

    父组件访问子组件 c h i l d r e n 或 children或 childrenrefs

    1. $children 得到的是一个 数组

      this.$children[].访问对象
      
    2. $refs 得到的是一个 对象

      this.$refs.添加ref的数值.访问对象
      
    3. 实例

    <div id="app">
    	<cpn></cpn>
    	
    	<cpn ref="aaa"></cpn>
    	<button type="button" @click="btnClick">点我</button>
    </div>
    <template id="cpn">
    	<div>
    		我是子组件
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		methods: {
    			btnClick() {
    				// 1 通过$children去拿子组件中的值
    				// // 拿到的子组件是一个数组类型的
    				// // console.log(this.$children);
    				// // 通过$children调用子组件的showMessage方法
    				// // this.$children[0].showMessage();
    				// // this.$children[0].name;
    				// for (let c of this.$children) {
    				// 	// 打印输出showMessage
    				// 	c.showMessage();
    				// 	// 打印输出xiaochen
    				// 	console.log(c.name);
    				// }
    				
    				// 2 通过$refs去拿子组件中的值
    				// this.$refs默认是一个空对象
    				console.log(this.$refs);
    				// 要使用$refs取值,需要在标签上面添加ref属性,然后通过this.$refs.ref属性值拿值
    				// 打印输出 showMessage
    				this.$refs.aaa.showMessage();    
    				// 打印输出 xiaochen
    				console.log(this.$refs.aaa.name);    
    			}
    		},
    		components: {
    			cpn: {
    				template: `#cpn`,
    				data() {
    					return {
    						name: 'xiaochen'
    					}
    				},
    				methods: {
    					showMessage() {
    						console.log('showMessage');
    					}
    				}
    			}
    		}
    	})
    </script>
    

    子组件访问父组件 p a r e n t , parent, parentroot

    1. $parent

      this.$parent.访问父组件的属性
      
    2. $root

      // 访问根组件,Vue实例
      this.$root
      

    实例:

    <div id="app">
    	<cpn>
    	</cpn>
    </div>
    <template id="cpn">
    	<div>
    		<h2>我是cpn组件</h2>
    		<ccpn></ccpn>
    	</div>
    </template>
    <template id="ccpn">
    	<div>
    		<h2>我是子组件</h2>
    		<button @click="btnClick">按钮</button>
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    				
    			}
    		},
    		components: {
    			cpn: {
    				template: `#cpn`,
    				data() {
    					return {
    						name: '我是cpn组件的name'
    					}
    				},
    				components: {
    					ccpn: {
    						template: `#ccpn`,
    						methods: {
    							btnClick() {
    								// 1 访问父组件$parent
    								// 打印出来是一个VueComponent对象
    								console.log(this.$parent);
    								// 打印输出 我是cpn组件的name
    								console.log(this.$parent.name);
    								
    								// 2 访问根组件$root
    								// 打印Vue 实例
    								console.log(this.$root);
    							}
    						}
    					}
    				}
    			}
    		}
    	})
    </script>
    

    插槽slot(组件化高级)

    为什么使用组件的插槽:

    • 为了让我们封装的组件更加具有扩展性
    • 让使用者可以决定组件内部的一些内容到底展示什么

    插槽的基本使用

    使用slot插槽,占据位置,在使用的时候传入对应的值,然后传入的值自己会填补插槽占据的位置。

    插槽的基本使用:

    1. 插槽的基本使用
    2. 插槽的默认值
    3. 如果有多个值,同时放入组件进行替换时,一起作为替换元素
    <div id="app">
    	<cpn></cpn>
    	<hr />
    	<cpn>
    		<button type="button">点我</button>
    	</cpn>
    	<hr />
    	<cpn><b>我是传入值</b></cpn>
    </div>
    <template id="cpn">
    	<div>
    		<h2>我是组件</h2>
    		<slot></slot>
    		<h5>content</h5>
    		<!-- 给插槽添加一个默认值,调用的时候没有加别的参数,就使用默认值,有参数,就是用传递的值 -->
    		<slot><button>我是插槽传递的默认值</button></slot>
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		components: {
    			cpn: {
    				template: `#cpn`
    			}
    		}
    	})
    </script>
    

    如何封装插槽

    抽取共性,保留不同。

    • 最好的方式就是将共性抽取到组件中,将不同暴露为插槽
    • 一旦预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容
    • 是搜索框,还是文字,还是菜单,由调用者自己来决定

    具名插槽

    给插槽设置name值,然后使用的使用根据solt等于的name值进行替换。

    <div id="app">
    	<cpn>
    		<!-- 替换name为center插槽 -->
    		<h1 slot="center">标题</h1>
    	</cpn>
    </div>
    <template id="cpn">
    	<div>
    		<slot name="left">
    			<h2>我是左边插槽</h2>
    		</slot>
    		<slot name="center">
    			<h2>我是中间插槽</h2>
    		</slot>
    		<slot name="right">
    			<h2>我是右边插槽</h2>
    		</slot>
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    
    			}
    		},
    		components: {
    			cpn: {
    				template: `#cpn`
    			}
    		}
    	})
    </script>
    

    编译的作用域

    父模板的所有东西都会在父级作用域内编译,子组件模板的所有东西都会在自己作用域内编译。

    <div id="app">
    	<!-- 这个是根据实例里面的isShow来决定的 -->
    	<!-- 命令使用时不关心组件的位置,只关心作用域 -->
    	<!-- 显示  app的data中的isShow是true -->
    	<cpn v-show="isShow"></cpn>
    </div>
    <template id="cpn">
    	<div>
    		<h2>我是子组件</h2>
    		<!-- 不显示 -->
    		<!-- cpn组件中的isShow是false -->
    		<button v-show="isShow"></button>
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    				isShow: true
    			}
    		},
    		components: {
    			cpn: {
    				template: `#cpn`,
    				data() {
    					return {
    						isShow: false
    					}
    				}
    			}
    		}
    	})
    </script>
    

    作用域插槽

    作用域插槽的目的就是:

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

    实例:

    • 子组件中包括一组数据,比如:pLanguages[‘Javascript’, ‘Python’, ‘Swift’, ‘Go’, ‘C++’]

    • 需要在多个界面进行展示:

      • 某些界面是以水平方向——展示的
      • 某些界面是以列表形式展示的
      • 某些界面直接展示——一个数组
    • 内容在子组件,希望父组件告诉我们如何展示?

      • 利用slot插槽就可以了
    <div id="app">
    	<!-- 子组件默认展示 -->
    	<cpn></cpn>
    	
    	<!-- 拿到子组件中的数据,然后在父组件中展示成不同的样式  -->
    	<!-- 目的:获取子组件中的pLanguages -->
    	<cpn>
    		<template slot-scope="slot">
    			<!-- 通过slot引用插槽对象 -->
    			<!-- 通过slot.data     拿到的就是  子组件中传递的:data="pLanguages" -->
    			<span v-for="item in slot.data">{{item}}  -</span>
    			<div>{{ slot.data.join(' - ')}}</div>
    		</template>
    	</cpn>
    </div>
    <template id="cpn">
    	<div>
    		<!-- 这里data可以为任何值  -->
    		<slot :data="pLanguages">
    			<ul>
    				<!-- 子组件展示 -->
    				<li v-for="item in pLanguages">{{ item }}</li>
    			</ul>
    		</slot>
    	</div>
    </template>
    <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
    	const app = new Vue({
    		el: '#app',
    		data() {
    			return {
    				isShow: true
    			}
    		},
    		components: {
    			cpn: {
    				template: `#cpn`,
    				data() {
    					return {
    						pLanguages: ['Javascript', 'Python', 'Swift', 'Go', 'C++']
    					}
    				}
    			}
    		}
    	})
    </script>
    

    模块化开发

    js原始功能:

    • 做表单验证活动话
    • 随着ajax的出现,前后端开始分离,为了应对代码量的与日俱增,将js分成多个js文件来编辑
    • 但这种方式依然不能避免一些灾难性问题:
      • 全局变量同名
      • js文件过多,执行顺序的问题
    • 解决:使用闭包()() ————》代码不可复用
      • 将每一个js文件封装成一个闭包,在闭包中通过创建空对象,将使用的值存入空对象中,然后return回去
      • 在别的js文件使用的时候,通过封装的闭包名.要使用的对象

    常见的模块化规范:

    CommonJS,AMD,CMD,也有ES6中的Modules

    CommonJS只是一个规范,CommonJS的实现是node.js。

    CommonJS

    模块化的两个核心:导出(export)和导入(require)

    CommonJS的导出:

    moule.export = {
    	name: 'xiaochen',
    	doit(a, b) {
    		return a + b;
    	}
    }
    
    

    CommonJS的导入:

    //CommonJS模块
    let { name,doit } = require('moduleA');
    
    //等同于
    let m = require('moduleA');
    let name = m.name;
    ...
    

    ES6的模块化实现

    export

    export指令用于导出变量:

    export let name = 'xiaochen'
    export let age = 18
    export let dream = 'free'
    

    也可以:

    let name = 'xiaochen'
    let age = 18
    let dream = 'free'
    
    export {
    	name, age, dream
    }
    

    导出函数和类:

    export function sum(a, b) {
        return a + b;
    }
    
    export class Person {
        run() {
            console.log('想上学的第一天');
        }
    }
    
    import {sum, Person} from './a.js'
    // 实例化类
    const p = new Person();
    // 调用类里面的函数
    p.run();
    

    export default:

    某些情况下,一个模块包含某个功能,我们并不希望给这个功能命名,而且让导入这自己来命名

    • 这个时候就可以使用 export default
    • 注意:export default 在同一个模块中,不允许同时存在多个
    const time = '二零二零年四月七日'
    
    // 1 
    export { time }
    // 2
    export const time = '二零二零年四月七日'
    //要使用上面的数据
    import {time} from 'a.js'
    
    // 在一个js中文件中,只能有一个default导出
    export default time
    import t from 'a.js'
    
    

    import

    export指令导出了模块对外提供的接口后,我们就可以通过import命令来加载这个对应的模块了

    • 首先我们需要在HTML代码中引入两个js文件,并且类型需要设置module

      <script src = "info.js" type = "module"></script>
      <script src = "main.js" type = "module"></script>
      
    • import指令用于导入模块内容,比如mian.js的代码

      import {name, age, sex} from './info.js'
      console.log(name, age, sex);
      
    • 统一全部导入

      import * as info from './info.js'
      console.log(info.name);
      

    webpack

    认识webpack

    什么是webpack?

    官网:webpack.js.org

    从本质上将,webpack是一个现代的JavaScript应用的静态模块打包工具。

    • 静态
    • 打包

    和grunt/gulp的对比

    • grunt/gulp的核心是Task
      • 我们可以配置一系列的task,并且定义task要处理的事物(例如ES6,ts转换,图片的压缩,scss转化成css)
      • 之后让grunt/gulp来依次执行这些task,而且让它流程自动化
      • grunt/gulp也被称为前端自动化任务管理工具
    • 什么时候用到grunt/gulp
      • 如果工程模块依赖非常简单,甚至是没有用到模块化的概念
      • 只要进行简单的合并,压缩,就使用grunt/gulp即可
      • 但是如果整个项目使用了模块化管理,而且相互依赖非常强,我们就可以使用更加强大的webpack
    • gulp和webpack的区别
      • grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心
      • webpack更加强调模块化开发管理,而文件压缩合并,预处理功能,是他附带的功能

    webpack的安装

    • webpack是基于node.js的
    • node为了可以正常的运行执行很多代码面必须其中包含很多包
    • 在安装node时,会自动安装npm(node package manager)

    查看node版本:

    node -v
    

    全局安装webpack(这里我们先制定版本号3.6.0,因为vue cli2依赖该版本):

    1. 查看电脑中有没有安装过webpack

      webpack --version  或者    webpack -v
      
    2. 没有 安装

      全局安装webpack:

      npm install webpack@3.6.0 -g
      

      本地安装webpack:

      --save-dev是开发时依赖【devDependencies】,项目打包后不需要继续使用

      npm install webpack@3.6.0 --save-dev
      

    webpack的起步

    文档解释:

    dist文件distribution(发布)
    文件解释
    src文件主要文件,一般项目的文件都写在src这个文件夹里面

    打包:

    // webpack  打包文件main.js的路径   打包成dist下面的bundle.js文件
    // webpack在打包的时候会自动处理依赖文件
    // 所以只需要打包入口文件就好了
    webpack ./src/main.js ./dist/bundle.js
    

    webpack的配置

    配置webpack让项目在运行的时候,直接webpack就可以运行项目,不需要webpack ./src/main.js ./dist/bundle.js这样运行

    步骤:

    1. 在项目文件中创建webpack.config.js文件

    2. 给webpack.config.js添加配置

      // path 依赖了node中的path包,所以要安装node中的所有依赖项
      // npm init --yes  安装所有依赖包
      // 就会去全局找path
      cost path = require('path');
      
      module.exports = {
      	// 入口
      	entry: './src/main/.js',
      	// 出口
      	output: {
      		// 路径  path  是绝对路径
      		// 动态获取路径
      		path: path.resolve(__dirname, 'dist'),
      		// 文件名   bundle  打包
      		filename: 'bundle.js'
      	}
      }
      
    3. pacjage.json中自定义启动

      为了在命令行工具中能够 通过 npm run build 运行项目,在package.json文件的script脚本中添加依赖项

      让我们在执行npm run build命令的时候来package.json文件中找到webpack

      当在命令行工具中执行npm run build的时候相当于执行webpack命令,运行的时候num run build会先去查找本地的webpack,这样防止因webpack版本的问题而引发错误

      "build": "webpack"
      

      通过npm run build打包后的文件是全局的

    loader的使用

    • loader是webpack中一个非常核心的概念

    • webpack用来做什么呢?

      • 在我们之前的实例中,我们主要是用webpack来处理我们写的js代码,并且webpack会自动处理js之间相关的依赖
      • 但是,在开发中我们不仅仅有基本的js代码处理,我们也需要加载css,图片,也包括一些高级的将ES6转成ES5的代码,将scss,less转成css,将.jsx,vue文件转成js文件等等。
      • 对于webpack本身的能力来说,对于这些转化是不支持的
      • 那怎么办呢?给webpack扩展对应的loader就可以了。
    • loader使用过程:

      • 步骤一:通过npm安装需要使用的loader

        • css-loader

          npm install --save-dev css-loader
          
        • style-loader

          npm install --save-dev style-loader
          
      • 步骤二:在webpack.config.js中的modules关键字下进行配置

        在module中css-loader只负责将css文件进行加载,style-loader将样式添加到DOM中

        使用多个loader时,是从右向左

        module: {
            rules: [
                {
                    test: /\.css$/
                    use: ['style-loader', 'css-loader']
                }
            ]
        }
        
      • 步骤三:配置,也就是再次打包,npm run build

    less文件处理–准备

    要想使用less文件更改样式要安装less-loader:

    npm install --save-dev less-loader less
    

    在webpack.config.js文件中配置less:

    // webpack.config.js
    module.exports = {
        ...
        module: {
            rules: [{
                test: /\.less$/,
                use: [{
                    loader: "style-loader" // creates style nodes from JS strings
                }, {
                    loader: "css-loader" // translates CSS into CommonJS
                }, {
                    loader: "less-loader" // compiles Less to CSS
                }]
            }]
        }
    };
    

    图片配置

    下载url-loader:

    npm install --save-dev url-loader
    

    配置url-loader:

    module.exports = {
      module: {
        rules: [
          {
            test: /\.(png|jpg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  // 当加载的图片,小于limit时,会将图片编译成base64字符串形式
                  // 当加载的图片,大于limit时,会使用file-loader模块进行加载,通过webpack打包后会编译成base64字符串的形式
                  limit: 8192	// 8192 8kb
                  
                  // 打包后webpack自动帮我们生成一个非常长的名字,但真是开发中,我们可能对打包图片的名字有一定的要求,比图将所有的图片放在一个文件夹中,跟图片原来的名称,同时也要防止重复
                   // [name]:图片原来的名字   [hash:8]:哈希值保留8位  [ext]:图片的扩展名
                   name: 'img/[name].[hash:8].[ext]'
                }
              }
            ]
          }
        ]
      }
    }
    

    安装file-loader:

    npm install --save-dev file-loader
    

    安装后,文档中使用的图片是打包后dist文件夹中的图片,

    在webpack.config.js文件配置图片使用的路径:

    在output中加入publicPath

    output: {
        publicPath: 'dist/'
    }
    

    ES6语法处理

    ES6的语法直接转成ES5,需要使用babel。

    在webpack中直接使用babel对应的loader就可以了。

    安装:

    npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
    

    配置webpack.config.js文件:

    env:environment环境的缩写。

    module: {
      rules: [
        {
          test: /\.js$/,
          // exclude:排除
          // include:包含
          exclude: /(node_modules|bower_components)/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['es2015']
            }
          }
        }
      ]
    }
    

    webpack中配置Vue

    • 在项目中使用vue.js进行开发,那么必须对其有依赖,所以我们先要进行安装:

      --save dev是开发时依赖,因为我们后续是在实际项目中使用vue的,所以并不是开发时依赖,使用--save

      npm install vue --save
      
      // 简写
      npm install vue -S
      
    • 使用vue进行开发

      // 导入vue
      import Vue from 'vue'
      
      //使用
      new Vue({
          el: '#app',
          ...
      })
      
    • vue在发布的时候,发布了两个版本

      • runtime-only

        • 代码中,不可以有任何的template
      • runtime-complier

        • 代码中,可以有template,因为有complier可以用于编译template
      • 要解决这个问题,只需要在webpack.config.js中配置

        resolve: {
            // 文件引入时省略后缀名配置
            extensions: ['.js', '.css', '.vue'],
            // alias 别名
            alias: {
                // 如果导入vue后,去vue文件中去找vue.esm.js文件,这个文件中包含了complier
                'vue$':'vue/dist/vue.esm.js'
            }
        }
        

    el和template的区别,及vue文件的封装

    1. template在解析的时候会替换el,再去修改html中的代码

    2. 但是如果将所有替换的代码都写在template里面,看着就很感觉很复杂,我们可以将template中的信息提取成一个组件

      // ------------------------------2.app.js文件------------------------------------
      // App对象中的代码可以封装到一个app.js文件里面
      export default {
          template: 
          `
      		<div>
      			....
      		</div>
      	`,
          data() {
              return {
                  
              }
          }
          ...   // 将所有的内容抽取到一个组件里面使用
      }
      
      // -----------------------------3.创建App.vue文件--------------------------------
      //让模板于组件分离
      <template>
          <div>
      		....
      	</div>
      </template>
      
      <script>
          export default {
      		name: "App",
              data() {
             		return {
                  
              	}
          	}
      		...
      	}
      </script>
      
      <style>
          //样式
      </style>
      
      
      // ------------------------------1.main.js文件------------------------------------
      //const App = {
      //    template: 
      //    `
      //		<div>
      //			....
      //		</div>
      //	`,
      //    data() {
      //        return {
                  
      //        }
      //    }
      //    ...   // 将所有的内容抽取到一个组件里面使用
      //}
      
      
      // 引入App组件内容
      //import App from './vue/app'
      import App from './vue/App.vue'
      new Vue({
          el: '#app',
          template: '<App />',
          components: {
              App	// 在组件里面注册App
          }
      })
      

      但是在编译过程中不能识别App.vue文件,所以我们需要对vue文件进行一个封装,就要使用vue-loadervue-template-complier

      安装:

      vue-loader让vue文件进行一个加载,vue-template-complier 对vue文件进行编译

      npm install vue-loader vue-template-complier --save-dev
      

      配置:

      {
          test: /\.vue$/,
          use: ['vue-loader']
      }
      

      因为vue-loader版本的原因,可能会报错,说vue-loader was used without the corresponding plugin,在package.json文件中将vue-loader的版本改成^13.0.0(13到14版本之间),然后在命令行工具中执行npm install重新安装一下

    plugin

    • plugin是什么?
      • plugin是插件的意思,通常是用于对某个现有的框架的进行扩展
      • webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等。
    • loader和plugin的区别:
      • loader主要用于转换某些类型的模块,它是一个转换器
      • plugin是插件,它是对webpack本身的一个扩展,是一个扩展器。
    • plugin的使用过程:
      • 通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
      • 在webpack.config.js中的plugins中配置插件

    添加版权的plugin

    BannerPlugin,属于webpack自带的插件。

    修改webpack.config.js的文件:

    const path = require('path');
    //导入webpack
    const webpack = require('webpack');
    
    modeule.exports = {
       ...
       plugins: [
            new webpack.BannerPlugin('最终版权归aaa所有')
       ]
    }
    

    重新打包:

    npm run build/webpack
    

    打包html的plugin

    • 目前,我们的index.html页面存放在项目的根目录下

      • 在真实发布项目的时候,发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html文件,那么打包的js文件也就没有意义了
      • 所以我们需要将index.html文件打包到dist文件夹中,这个时候就可以使用HtmlWebpackPlugin插件
    • HtmlWebpackPlugin插件可以:

      • 自动生成一个index.html文件(可以指定模板来生成)
      • 将打包的js文件,自动通过script标签插入到body中
    • 安装HtmlWebpackPlugin插件

      npm install html-webpack-plugin --save-dev
      
    • 使用插件,修改webpack.config.js文件中plugins部分的内容

      • 这里的template表示根据什么模板来生成index.html

      • 另外我们需要删除之前在output中添加的publicPath属性

      • 否则插入的script标签中的src可能会有问题

        const path = require('path');
        //导入webpack
        const webpack = require('webpack');
        // 导入HtmlWebpackPlugin插件
        const HtmlWebpackPlugin = require('html-webpack-plugin');
        
        modeule.exports = {
           ...
           plugins: [
                new webpack.BannerPlugin('最终版权归aaa所有'),
               	// 这样使用之后,就会在文件中的dist文件夹下面生成index.html文件
                new HtmlWebpackPlugin({
                    // 让template根据index.html文件来生成index.html
                    template: 'index.html'
                })
           ]
        }
        

    js压缩的Plugin

    • 在项目发布之前,我们必须要对js等文件进行压缩处理

      • 对js文件进行压缩,使用的是第三方插件unlifyjs-webpack-plugin,并且版本号指定1.1.1,和cli2保持一致

        npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
        
    • 修改webpack.config.js文件,使用插件:

      const path = require('path');
      //导入webpack
      const webpack = require('webpack');
      // 导入unlifyjs-webpack-plugin插件
      // 在开发阶段不建议使用uglifyJsPlugin插件,代码在修改后不宜调试
      const uglifyJsPlugin = require('unlifyjs-webpack-plugin');
      
      module.exports = {
         ...
         plugins: [
              new webpack.BannerPlugin('最终版权归aaa所有'),
             	new uglifyJsPlugin()
         ]
      }
      
    • 查看打包后的bunlde.js文件,最后已经被压缩过了

    搭建本地服务器

    • webpack提供了一个可选的本地服务器,这个本地服务器基于node.js搭建,内部使用express框架,可实现浏览器自动刷新显示修改后的结果。

    • 不过它是一个单独的模块,在webpack中使用之前需要先安装

      npm install --save-dev webpack-dev-server@2.9.1
      
    • devserver也是作为webpack中的一个选项,选项本身可以设置以下属性:

      • contentBase:为那个文件提供本地服务,默认是根文件夹,我们这里要填写./dist
      • port: 端口号
      • inline:页面实时刷新
      • historyApiFallback:在SPA页面中,依赖HTML5的history模式
    • webpack.config.js文件配置修改:

      devServer: {
          contentBase: './dist',
          inline: true
      }
      
    • 我们还可以配置package.json中的script:

      • –open参数标识直接打开浏览器

        "build": "webpack"
        "dev": "webpack-dev-server --open"
        

    配置完成后运行:

    ​ 在命令窗口通过npm run dev运行

    配置(webpack.config.js)结构分离

    将开发时依赖和发布时依赖分离。

    • 在主文件夹下创建build文件夹,在build文件夹下面创建base.config.js(公共),prod.config.js(开发时依赖包)和dev.config.js(运行时依赖)

    • 安装webpack-merge,将分离的文件进行合并

      npm install webpack-merge --save-dev
      
    • 使用

      base.config.js中:

      const path = require('path');
      //导入webpack
      const webpack = require('webpack');
      
      modeule.exports = {
      	// 入口
      	entry: './src/main/.js',
      	// 出口
      	output: {
      		// 路径  path  是绝对路径
      		// 动态获取路径
      		path: path.resolve(__dirname, 'dist'),
      		// 文件名   bundle  打包
      		filename: 'bundle.js'
      	},
      	module: {
      		rules: [{
      			test: /\.css$/
      			use: ['style-loader', 'css-loader']
      		}]
      	},
      	plugins: [
      		new webpack.BannerPlugin('最终版权归aaa所有')
      		new HtmlWebpackPlugin({
      			// 让template根据index.html文件来生成index.html
      			template: 'index.html'
      		})
      	]
      }
      

      prod.config.js中:

      const uglifyJsPlugin = require('unlifyjs-webpack-plugin');
      
      // 导入webpack-merge
      const webpackMerage = require('webpack-merge');
      
      //拿到baseConfig 
      const baseConfig = require('./base.config');
      
      //将config文件合并导出
      module.exports = webpackMerage(baseConfig, {
         ...
         plugins: [
              new webpack.BannerPlugin('最终版权归aaa所有'),
             	new uglifyJsPlugin()
         ]
      })
      

      dev.config.js中:

      // 导入webpack-merge
      const webpackMerage = require('webpack-merge');
      
      //拿到baseConfig 
      const baseConfig = require('./base.config');
      
      module.exports = webpackMerage(baseConfig,{
          devServer: {
          	contentBase: './dist',
          	inline: true
      	}
      })
      

      最后在使用时候,将package.json文件中的build改为:

      更改一下config的指向:

      "build": "webpack --config ./build/prod.config.js",
      "dev": "webpack-dev-server --open --config ./build/dev.config.js"
      

      然后使用:

      run run dev
      

      但是这样打包后的文件在build文件下面生成的dist文件夹里面,为了解决这个问题,就将base.config.js文件中output下的path改为:

      path: path.resolve(__dirname, '../dist')
      

    Vue cli脚手架详解

    什么是Vue CLI

    • CLI是Command-Line Interface,翻译为命令行界面,俗称脚手架
    • Vue CLI是官方发布的vue.js项目脚手架
    • 使用vue-cli可以快速搭建Vue开发环境及对应的webpack配置

    Vue CLI使用前提-Node

    脚手架应用于webpack,webpack基于node。

    Vue CLI的使用

    • 安装Vue脚手架,-g(global:全局的)

      npm install -g @vue/cli
      
    • 注意:上面安装的是Vue CLI3的版本,如果需要想按照Vue CLI2的方式初始化项目是不可以的。

      安装Vue CLI2:

      npm install -g @vue/cli-init
      
    • 安装完成后,查看是否安装成功:

      vue --version
      
    • Vue CLI2初始化项目:

      • vue init webpack my-project(项目名称)

    在这里插入图片描述

    • Vue CLI3初始化项目

      • vue create my-project

        chrome中的 v8引擎(使用c++实现,v8是开源的),将js代码直接编译成二进制代码,在浏览器中执行

        js -》 浏览器

        js -》字节码 -》浏览器

      在这里插入图片描述

    视频材料链接: https://pan.baidu.com/s/1dxV3TSKpHoFhZo-oM3stFg
    提取码: epuk

    展开全文
  • Web前端Vue2.0 + Vue3.0 全套入门到精通教程
  • vuejs2从入门到精通视频教程

    千次阅读 2018-03-26 09:06:39
    介绍2.vue实例3.模板语法4.计算属性和观察者5.Class与Style绑定6.条件渲染7.列表渲染8.事件处理9.表单输入绑定10.1.组件(1)10.2.组件(2)11.案例:下拉选择菜单12.案例:任务管理列表二、高级部分13.深入响应式原理14...

    一、基础部分

    0.课件

    1.介绍

    2.vue实例

    3.模板语法

    4.计算属性和观察者

    5.Class与Style绑定

    6.条件渲染

    7.列表渲染

    8.事件处理

    9.表单输入绑定

    10.1.组件(1)

    10.2.组件(2)

    11.案例:下拉选择菜单

    12.案例:任务管理列表


    二、高级部分

    13.深入响应式原理

    14.过渡_动画

    15.混合

    16.自定义指令

    17.渲染函数_JSX

    18.插件_过滤器

    19.单文件组件(vue-loader、vue-cli)

    20.路由(vue-router)

    21.状态管理(vuex)

    22.服务端渲染

    23.axios讲解


    三、项目:面试简历管理系统

    24.项目介绍及初始化

    25.顶部导航-职位类别

    26.中间主体-面试者列表(1)

    27.中间主体-面试者列表(2)

    28.底部人选&上线部署


    视频观看:http://www.iqiyi.com/playlist470545402.html


    展开全文
  • vue-cli2.x脚手架的使用 参考链接:https://github.com/vuejs/vue-cli/tree/v2#vue-cli-- 安装: npm install -g vue-cli 用法: $ vue init < template-name > < project-name > 例: $ vue...
  • Vue从入门到精通

    2021-09-01 12:55:32
    第2章 vue开发基础(上) 1.vue组件 vue可以进行组件化开发,组件是vue的基本结构单元,开发过程中使用起来非常方便灵活,只需按照vue规范定义组件,将组件渲染页面即可,组件可实现复杂的页面结构,提高代码复用...
  • 1. Vue.js课程介绍 2. Vue的认识和特点介绍 3. Vue.js安装 安装方式: CDN引入:选择开发环境版本<!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src=...
  • Vue学习从入门到精通(二)

    千次阅读 2018-08-09 18:38:17
      《Vue学习从入门到精通(一)》我们开启了Vue的学习之路,今天我们就来一块学习一下Vue.js中的内部指令。 v-if v-if指令可以完全根据表达式的值在DOM中生成或移除一个元素。书中源码如下: &...
  • Vue.js 教程、《HTML5从入门到精通》中文学习教程、CSS权威指南(第三版)(jb51.net)三本书扫描版
  • vue 入门到精通.txt

    2020-04-20 11:42:23
    vue 入门到精通
  • Vue学习从入门到精通(三)

    千次阅读 2018-08-10 11:15:56
      这一篇文章主要说一下Vue对数组的各种操作。在说Vue之前,我们先了解一下javascript中对数组操作的常见函数。 函数 说明 push() 这个函数主要是在数组的末尾添加一个新的元素 pop()...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,566
精华内容 1,826
关键字:

vue从入门到精通教程

vue 订阅