VUE的简单入门

VUE

        • 1.了解VUE
          • 1.1VUE是一个渐进式的框架,什么时渐进式的?
          • 1.2VUE特点和web开发常见的高级功能
          • 1.3学习的VUE的前提技术
          • 1.4VUE.js安装
            • 1.4.1直接CDN引入
            • 1.4.2下载和引入
            • 1.4.3npm安装
          • 1.5入门案例
            • 1.5.1响应式
            • 1.5.2 v-for指令,自动读取数据,响应式的
            • 1.5.3v-on指令
          • 1.6MVVM:Model VueModel View
          • 1.7创建VUE实例传入的options
          • 1.8VUE声明周期
        • 2.VUE基本语法
          • 2.1插值操作
            • 2.1.1Mustache语法
            • 2.1.2v-once
            • 2.1.3v-html
            • 2.1.4v-text
            • 2.1.5v-pre
            • 2.1.6v-cloak
          • 2.2语法糖(实际开发中推荐使用)
            • 2.2.1v-bind
            • 2.2.2v-on
          • 2.2.3v-if v-else-if v-else(不推荐使用,可以使用计算属性来替代
            • 2.2.4v-show
            • 2.2.5v-for
            • 2.2.6数组有哪些方法是响应的
            • 2.2.7v-model数据和表单元素的双向绑定
          • 2.3计算属性
            • 2.3.1计算属性的入门使用
            • 2.3.2赋值操作
            • 2.3.3计算属性的setter和getter
            • 2.3.4计算属性和methods的对比
        • 3.组件化开发
          • 3.1什么是vue.js
          • 3.2注册组件化的基本步骤
          • 3.3全局组件和局部组件
          • 3.4父子组件
          • 3.5注册组件(语法糖)
          • 3.6组件模板分离(script和template标签都能实现)
          • 3.6组件data必须是函数
            • 3.6.1为什么必须是函数
          • 3.7父子组件通讯
            • 3.7.1父传子
            • 3.7.2props中的驼峰命名(注意事项)
            • 3.7.3子传父---自定义事件emit
            • 3.7.4父子通讯实现双向绑定
            • 3.7.5父子组件的访问方式:$children
            • 3.7.6子组件访问父组件\$parent或\$root
          • 3.8slot
            • 3.8.1为什么使用slot
            • 3.8.2具名插槽
            • 3.8.3编译作用域
            • 3.8.4作用域插槽
          • 3.9模块化开发
            • 3.9.1为什么需要模块化(全局变量名冲突)
            • 3.9.2早期使用模块化(匿名函数)
            • 3.9.3常见的模块化规范
            • 3.9.4CommonJS模块化(核心导入 导出)
            • 3.9.5ES6模块化(export/import) type='module'才支持
        • 4.webpack
          • 4.1认识webpack
          • 4.2webpack的安装
          • 4.3webpack起步
            • 4.3.1webpack打包出现问题
            • 4.3.2处理方案
          • 4.4webpack的基本使用
          • 4.5webpack的配置
            • 4.5.1创建webpack.config.js
            • 4.5.2loader的使用([https://www.webpackjs.com/](https://www.webpackjs.com/))
            • 4.5.3webpack中的配置VUE
            • 4.5.4el与template区别
            • 4.5.5plugin的使用
          • 4.6搭建本地服务器(开发时使用)
            • 4.6.1搭建本地服务器,在开发时,修改或开发,不需要重写打包
            • 4.6.2webpack配置文件分离
        • 5.Vue Cli详解
          • 5.1什么是Vue Cli
          • 5.2Vue Cli使用前提 -------->node webpack
          • 5.3安装Vue脚手架
          • 5.4脚手架初始化项目
          • 5.5Vue Cli2初始化项目详解
          • 5.6ESLint规范
        • 6.Vue基础语法
          • 6.1runtime-compiler与runtime-only区别
          • 6.2createElement函数
          • 6.3npm run build与npm run dev区别
          • 6.4vue-cli3与2区别
          • 6.5Vue-Cli3创建项目
            • 6.5.1Cli3初始化项目详解
            • 6.5.2Cli3配置文件修改
          • 6.6补充点ES6
            • 6.6.1ES6箭头函数
            • 6.6.2this的使用
            • 6.6.3Promise使用
          • 6.6.7vite创建vue3
            • 1.初始化
        • 7.Vue-router
          • 7.1认识路由
          • 7.2url的hash和html5的history
          • 7.3目前前端流行的三大框架,都有自己的路由实现
            • 7.3.1vue-router
            • 7.3.2vue-router是基于路由和组件的
            • 7.3.3安装vue-router
            • 7.3.4使用vue-router,来配置路由路径
            • 7.3.5使用vue-router
          • 7.4vue-router基本使用
            • 7.4.1路由的默认路径(网页打开显示的首页)
            • 7.4.2改变路由的方式有两种(URL路径是否显示#,如果不希望显示#,就使用history)
            • 7.4.3router-link补充
            • 7.4.4路由跳转
            • 7.4.5动态路由
            • 7.4.6路由的懒加载
            • 7.4.7vue-router嵌套路由
            • 7.4.8vue-router参数传递(URL:协议://主机/路径?查询)
            • 7.4.9\$router和\$route由来(所有组件都继承vue原型)
          • 7.5vue-router导航守卫
            • 7.5.1解决方案1
            • 7.5.2解决方案2
            • 7.5.3组件内的守卫
            • 7.5.4keep-alive遇到vue-router
          • 7.6项目开发中资源引入路径问题
        • 6.Vuex详解
          • 6.1概述
          • 6.2单界面的状态管理
          • 6.3安装Vuex
          • 6.4Vuex状态管理图例
            • 6.4.1Mutations使用
          • 6.5Vuex核心概念
            • 6.5.1state
            • 6.5.2getters ----- 数据需要特殊处理
            • 6.5.3Mutation
            • 6.5.4mutations更新数据的适合,希望携带一些额外的参数
            • 6.5.5Mutations提交风格
          • 6.6Mutations响应规则
          • 6.6.1概述
            • 6.6.2Mutations常量类型(官方推荐使用)
          • 6.7action
            • 6.7.1概述
            • 6.7.2如果确实需要异步操作,解决方案
          • 6.8module
            • 6.8.1概述
            • 6.8.2局部状态暴露
          • 6.8.3补充知识点
        • 8.网络封装
          • 8.1选择什么网络模板
          • 8.2axios功能特点
          • 8.3支持多种请求方式
          • 8.4安装axios
          • 8.5axios的基本使用
          • 8.6axios发送并发请求
          • 8.7全局配置
          • 8.8axios的实例模块封装
            • 8.8.1为什么需要创建实例
            • 8.8.2axios封装方式很多,如下
          • 8.9axios的拦截器的使用

1.了解VUE

1.1VUE是一个渐进式的框架,什么时渐进式的?
  • 渐进式意味着你可以将Vue作为你应用的一部分嵌套其中,带来丰富的交互体验或者如果你希望将更多的业务逻辑使用vue,那么Vue的核心库以及其他生态系统,比如Core+Vue-router+Vuex,也可以满足你各种各样的需求
1.2VUE特点和web开发常见的高级功能
  • 解耦视图和数据
  • 可复用的组件
  • 前端路由技术
  • 状态管理
  • 虚拟DOM
1.3学习的VUE的前提技术
  • jQuery基础知识
  • HTML\CSS\JavaScript基础
1.4VUE.js安装
1.4.1直接CDN引入
<!--开发环境版本,包含了有帮助的命令行警告-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--生产环境版本,优化了尺寸和速度-->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
1.4.2下载和引入
<!--开发环境-->
https://vuejs.org/js/vue.js
<!--生产环境-->
https://vuejs.org/js/vue.min.js
1.4.3npm安装
  • 通过webpack和CGI的使用
1.5入门案例
1.5.1响应式
  • 当数据发生改变时,页面自动加载
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="../js/vue.js">script>
head>
    <body>
        <div id="app">
            <h1>{{message}}h1>
            <h2>{{name}}h2>
        div>
        <script type="text/javascript">
            //let(定义变量)/const(定义常量)
            //编程范式:声明式编程
            const app = new Vue({
                el: '#app',//用于挂载要管理的元素
                data: {//定义数据,该属性中通常会存储一些数据
                    message: "Hello World",
                    name: 'coderwhy'
                }
            });
            //原始JS的做法(编程范式:命令式编程)
            // 创建div元素,设置id属性
            // 定义变量叫message
            // 将message变量放在前面的div元素中显示
            //修改message的数据
            //将修改后的数据,重新替换到div
        script>
    body>
html>
1.5.2 v-for指令,自动读取数据,响应式的
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <script src="../js/vue.js">script>
    head>
    <body>
        <div id="app">
            <ul>
                <li v-for="item in movies">{{item}}li>
            ul>
        div>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWord',
                    movies: ['星际穿越',"大话西游","少年派的奇幻漂流","盗梦空间"]
                }
            });
        script>
    body>
html>
1.5.3v-on指令
  • 绑定事件,创建methods的方法,v-on:click可以通过语法糖:@click
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <script src="../js/vue.js">script>
    head>
    <div id="app">
        <h2>当前计数:{{counter}}h2>
        
        <button v-on:click="add">+button>
        <button v-on:click="sub">-button>
    div>
    <body>
        <script>
            const app = new Vue({
               el: '#app',
               data: {
                   counter: 0
               },
                methods: {
                   add: function(){
                       console.log("add执行");
                       this.counter++
                   },
                   sub: function(){
                       console.log("sub执行");
                       this.counter--
                    }
                }
            })
        script>
       
    body>
html>
1.6MVVM:Model VueModel View

VUE的简单入门_第1张图片

1.7创建VUE实例传入的options
  • options包含的属性
    • 详解:https://cn.vuejs.org/v2/api/
  • el
    • 类型:String/HTML Element
  • data
    • 类型:Object/Function(组件当中data必须是函数)
  • methods
    • 类型:{[key:string]: function}
1.8VUE声明周期

VUE的简单入门_第2张图片

2.VUE基本语法

  • 代码规范:两个空格最为规范
2.1插值操作
2.1.1Mustache语法
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
       <div id="app">
           
           <h2>{{message}}h2>
           
           <h2>{{firstName + lastName}}h2>
           <h2>{{firstName + ' ' + lastName}}h2>
           <h2>{{firstName}} {{lastName}}h2>
           <h2>{{counter * 2}}h2>
       div>
       <script src="../js/vue.js">script>
       <script>
           const app = new Vue({
           el: '#app',
           data: {
               message: 'HelloWorld',
               firstName: '大疆',
               lastName: '无人机',
               counter: 100
               }
           });
       script>
    body>
html>
2.1.2v-once
  • 如果显示的信息后续不需要再修改,使用v-once,可以提高性能
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2>{{message}}h2>
            
            <h2 v-once>{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld'
                }
            });
        script>
    body>
html>
2.1.3v-html
  • 解析含有html标签的数据
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2>{{message}}h2>
            
            <h2 v-html>{{url}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld',
                url: '百度一下'
                }
            });
        script>
    body>
html>
2.1.4v-text
  • 不推荐使用,不灵活,不能拼接数据,会直接覆盖标签里面的其他数据,只显示字符串
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2>{{message}}h2>
            
            <h2 v-text="message">h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld'
                }
            });
        script>
    body>
html>
2.1.5v-pre
  • 以原始的信息进行显示,跳过编译过程
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2>{{message}}h2>
            
            <h2 v-pre>{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld'
                }
            });
        script>
    body>
html>
2.1.6v-cloak
  • 通过v-cloak,配合css,[v-cloak]{display: none;},避免页面加载闪烁
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <style>
            [v-cloak]{
                display: none;
            }
        style>
    head>
    <body>
        <div id="app">
            <h2>{{message}}h2>
            <h2 v-cloak>{{message}}h2>
            
        div>
        <script src="../js/vue.js">script>
        //在Vue解析之前,div中有一个属性v-cloak
        //在Vue解析之后,div中没有一个属性v-cloak
        <script>
            setTimeout(function () {
                const app = new Vue({<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div id="app">
            <!--不能使用mustache语法-->
            <img v-bind:src="imgURL" alt="">
            <a v-bind:href="url">百度一下</a>
            <!--语法糖的写法-->
            <img :src="imgURL" alt="">
            <a :href="url">百度一下</a>
        </div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                imgURL: 'https://img.alicdn.com/imgextra/i2/4104649789/O1CN01M1dQGV2MBPfBS2fAT_!!4104649789-0-beehive-scenes.jpg_180x180xzq90.jpg_.webp',
                url: 'http:www.baidu.com'
                }
            });
        script>
    body>
html>
                    el: '#app',
                    data: {
                        message: 'HelloWorld'
                    }
                });
            },3000)
        script>
    body>
html>
2.2语法糖(实际开发中推荐使用)
2.2.1v-bind
  • 基本使用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <img v-bind:src="imgURL" alt="">
            <a v-bind:href="url">百度一下a>
            
            <img :src="imgURL" alt="">
            <a :href="url">百度一下a>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                imgURL: 'https://img.alicdn.com/imgextra/i2/4104649789/O1CN01M1dQGV2MBPfBS2fAT_!!4104649789-0-beehive-scenes.jpg_180x180xzq90.jpg_.webp',
                url: 'http:www.baidu.com'
                }
            });
        script>
    body>
html>
  • 动态绑定(class)
    • 对象语法
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <style>
            .active{
                color: aqua;
                font-family: "HoloLens MDL2 Assets";
            }
        style>
    head>
    <body>
        <div id="app">
            
            <h2 :class="active">{{message}}h2>
            
            
            <h2 :class="{active: isActive,line: isLine}">{{message}}h2>
            
            <h2 :class="getClasses()">{{message}}h2>
            <button @click="btnClick">按钮button>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld',
                active: 'active',
                isActive: true,
                isLine: false
                },
            methods: {
                btnClick: function () {
                    this.isActive = !this.isActive;
                },
                getClasses: function (){
                    return {active: this.isActive,line: this.isLine}
                }
            }
            });
        script>
    body>
html>
    • 数值语法
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <h2 :class="[active,line]">{{message}}h2>
            
            <h2 :class="getClasses()">{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld',
                active: 'active',
                line: 'line'
                },
            methods: {
                getClasses: function(){
                    return [this.active,this.line]
                }
            }
            });
        script>
    body>
html>
  • 动态绑定(style)
    • 写css属性名的时候:可以采用驼峰式(fontSize)或短横线式(font-size)
    • 对象语法
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            
            
            
            
            <h2 :style="{fontSize: finalSize+'px',backgroundColor: finalColor}">{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld',
                finalSize: 100,
                finalColor: 'aqua'
                }
            });
        script>
    body>
html>
    • 数值语法
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2 :style="[baseStyle,baseStyle1]">{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
            el: '#app',
            data: {
                message: 'HelloWorld',
                baseStyle: {backgroundColor: 'aqua'},
                baseStyle1: {fontSize: '100px'}
                }
            });
        script>
    body>
html>
2.2.2v-on
  • 基础使用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
       <div id="app">
           <h2>{{counter}}h2>
           
           <button @click="add()">+button>
           <button @click="sub()">-button>
       div>
       <script src="../js/vue.js">script>
       <script>
           const app = new Vue({
               el: '#app',
               data: {
                    counter: 0,
                  },
               methods: {
                   add(){
                       this.counter++;
                   },
                   sub(){
                      this.counter--;
                   }
               }
           });
       script>
    body>
html>
  • v-on参数
    • methods中定义方法,注意参数问题
      • 如果该方法不需要额外参数,那么方法后面可以不用添加括号
        • 如果方法本事中有一个参数,那么默认将原生事件event参数传递进去
      • 如果需要同时传入某个参数,同时需要event,可以通过**$event**传入事件
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <button @click="btnClick">按钮1button>
            <button @click="btnClick()">按钮2button>
           
            
            <button @click="btnClick2(123)">按钮2button>
            <button @click="btnClick2()">按钮2button>
            
            <button @click="btnClick2">按钮2button>
            
            
            <button @click="btnClick3('btn',$event)">按钮3button>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   },
                methods: {
                    btnClick(){
                        console.log("btnClick");
                    },
                    btnClick2(btn){
                        console.log("=================="+btn)
                    },
                    btnClick3(btn,event){
                        console.log("+++++++++++++"+btn,event)
                    }
                }
            });
        script>
    body>
html>
  • v-on修饰符
    • 特定情况下,拿到event可能需要进行一些事件处理
    • VUE提供了修饰符帮助方便处理某些问题
表达式 函数调用 效果
.stop 调用event.stopPropagation() 停止冒泡
.prevent 调用event.preventDefault() 阻止默认行为
.{keyCode|keyAilas} 只当事件是从待定建触发时回调
.native 监听组件根元素的原生事件
.once 只触发一次回调 点击回调只会触发一次
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <div @click="divClick">
                <button @click.stop="btnClick">按钮button>
            div>
            
            <form action="tengxu">
                <input type="submit" value="提交" @click.prevent="submitClick">
            form>
            
            <input type="text" @keyup.enter="keyUp">
            
            <input type="text" @keyup.13="keyUp">

            
            <button @click.once="onceClick">button>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   },
                methods: {
                    divClick () {
                        console.log("divClick")
                    },
                    btnClick () {
                       console.log("btnClick")
                    },
                    submitClick () {
                        console.log("submitClick")
                    },
                    keyUp () {
                        console.log("keyUp")
                    },
                    onceClick () {
                        console.log("onceClick")
                    }
                }
            });
        script>
    body>
html>
2.2.3v-if v-else-if v-else(不推荐使用,可以使用计算属性来替代
  • VUE的条件指令可以根据表达式的值在DOM渲染销毁元素组件
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2 v-if="isShow">{{message}}h2>
            <h2 v-else-if="score>90">{{fr}}h2>
            <h2 v-else>{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    isShow: true,
                    score: 95,
                    message: '合格',
                    desc: '不合格',
                    fr: '优秀'
                   }
            });
        script>
    body>
html>
  • input复用问题
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        
        <div id="app">
            <span v-if="isUser">
                <label for="username">用户账号label>
                <input type="text" id="username" placeholder="用户账号" key="username">
            span>
            <span v-else>
                <lable for="useremail">用户邮箱lable>
                <input type="text" id="useremail" placeholder="用户邮箱" key="useremail">
            span>
            <button @click="isUser != isUser">切换类型button>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    isUser: true,
                   }
            });
        script>
    body>
html>
2.2.4v-show
  • v-ifv-show非常相似
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <h2 v-if="isShow">{{message}}h2>
            <h2 v-show="isShow">{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    isShow: false,
                    message: 'HelloWorld'
                   }
            });
        script>
    body>
html>
2.2.5v-for
  • 遍历数组
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
           
            <ul>
                <li v-for="name in names">{{name}}li>
            ul>
            
            <ul>
                <li v-for="(item,index) in names">
                    {{item}}.{{index+1}}
                li>
            ul>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    names: ['大疆无人机','华为科技','魅族科技','方舟计划','全动态人工智能']
                   }
            });
        script>
    body>
html>
  • 遍历对象
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <ul>
                <li v-for="item in info">{{item}}li>
            ul>
            
            <ul>
                <li v-for="(value,key) in info">{{key}}---{{value}}li>
            ul>
            <ul>
            <li v-for="(value,key,index) in info">{{index}}.{{key}}---{{value}}li>
        ul>

        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    info: {
                        name: '大疆无人机',
                        age: 18,
                        height: 188
                    }
                   }
            });
        script>
    body>
html>
  • v-for添加key
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>

        <div id="app">
            
            
            <ul>
                <li v-for="item in letters" :key="item">{{item}}li>
            ul>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    letters: ['A','B','C','D','E']
                   }
            });
        script>
    body>
html>
2.2.6数组有哪些方法是响应的
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <ul>
                <li v-for="item in letters">{{item}}li>
            ul>
            <button @click="btnClick">button>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    letters: ['A','B','C','D','E']
                   },
                methods: {
                    btnClick(){
                        //1.push()方法,在数组最后面添加元素(一个或多个,逗号隔开)-----响应式的
                        this.letters.push('K');
                        //2.通过索引值修改数组中的元素-----非响应式的
                        this.letters[0] = 'L';
                        //pop()方法,删除数组中的最后一个元素-----响应式的
                        this.letters.pop();
                        //shift()方法,删除数组中的第一个元素-----响应式的
                        this.letters.shift();
                        //unshift()方法,在数组最前面添加元素(一个或多个,逗号隔开)-----响应式的
                        this.letters.unshift('AA');
                        //splice()方法,删除/插入/替换元素------响应式
                        //删除元素,第二个参数传入你要删除元素个数(如果不传值就删除后面元素)
                        //替换元素:第二个参数,表示我们要替换的的元素个数,后面用于替换前面的元素
                        //插入元素,第二个参数,传入0,并且后面添加元素
                        //splice(start)
                        this.letters.splice(2,2,'M','X');
                        this.letters.splice(3,0,'P','O','R');
                        //sort()方法,排序----响应式
                        this.letters.sort();
                        //reverse()方法,反转-----响应式
                        this.letters.reverse();
                        //set(要修改的对象,索引值,修改后的值)-----响应式
                        Vue.set(this.letters,0,'AAA');
                    }
                }
            });
        script>
    body>
html>
  • 实例展示
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <style>
            .active{
                color: aqua;
            }
        style>
    head>
    <body>
        <div id="app">
            <ul>
                <li v-for="(item,index) in movies"
                    :class="{active: currentIndex === index}"
                    @click="btnClick(index)"
                >{{item}}li>
            ul>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    movies: ['大疆无人机','麒麟芯片','华为通信','国家电网','达摩院'],
                    currentIndex: 0

                   },
                methods: {
                    btnClick(index){
                        this.currentIndex = index;
                    }
                }

            });
        script>
    body>
html>
  • 购物车案例(高阶函数)
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <style>
            table{
                border: 1px solid #e9e9e9;
                border-collapse: collapse;
                border-spacing: 0;
            }
            th,td{
                padding: 8px 16px;
                border: 1px solid #e9e9e9;
            }
            th{
                background-color: #f7f7f7;
                color: #5c6b77;
                font-weight: 600;
            }
        style>
    head>
    <body>
        <div id="app">
           <div v-if="list.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 list" v-show="item.count">
                       <td>{{item.id}}td>
                       <td>{{item.name}}td>
                       <td>{{item.date}}td>
                       
                       <td>{{item.price | showPrice}}td>
                       <td>
                           <button @click="decrement(index)">-button>
                           {{item.count}}
                           <button @click="increment(index)">+button>
                       td>
                       <td><button @click="removeHandle(index)">移除button>td>
                   tr>
                   tbody>
               table>
               <h2>总价格:{{totalPrice | showPrice}}h2>
           div>
            <h2 v-else>购物车为空h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    list: [
                        {
                            id: 1,
                            name: '《算法导论》',
                            date: '2008-9',
                            price: 85.00,
                            count: 1
                        },
                        {
                            id: 2,
                            name: '《Uxin编程艺术》',
                            date: '2010-11',
                            price: 59.00,
                            count: 2
                        },
                        {
                            id: 3,
                            name: '《编程珠玑》',
                            date: '2005-12',
                            price: 39.00,
                            count: 1
                        },
                        {
                            id: 4,
                            name: '《代码大全》',
                            date: '2008-7',
                            price: 129.00,
                            count: 2
                        },
                        {
                            id: 5,
                            name: '《编程艺术》',
                            date: '2010-9',
                            price: 88.00,
                            count: 1
                        },
                    ]
                   },
                methods: {
                   /* getFinalPrice(price){
                        return '¥'+price.toFixed(2);
                    }*/
                    decrement(index){
                        this.list[index].count--;
                    },
                    increment(index){
                        this.list[index].count++;
                    },
                    removeHandle(index){
                        this.list.splice(index,1);
                    }
                },
                computed: {
                  totalPrice(){
                      let totalPrice = 0;
                      //普通的for循环
                      /*
                      for (let i=0;i
                      //for (let i in this.list)
                      /*
                      for (let i in this.list){
                          totalPrice += this.list[i].price*this.list[i].count;
                      }
                      */
                      //for (let book of this.list)
                      /*
                      for (let book of this.list){
                          totalPrice += book.price*book.count;
                      }
                      */
                      //return totalPrice;
                      //reduce
                      return this.list.reduce(function(preValue,book){
                          return preValue + book.price*book.count;
                      },0)
                  }
                },
                filters: {
                    showPrice(price){
                        return '¥'+price.toFixed(2);
                    }
                }
            });
            //编程范式:命令式编程/声明式编程
            //编程范式:面向对象编程(第一公民:对象)/函数式编程(第一公民:函数)
            //filter/map/reduce
            //filter中的回调函数有一个要求:必须返回一个boolean值
            //true:返回true时,函数内部会自动将这次回调函数的n加入到新数组中
            //false:返回false时,函数内部会过滤掉这次的n

            const nums = [10,20,110,40,233,60,70,80];

            let total = nums.filter(n => n < 100).map(n => n*2).reduce((preValue,n) => preValue + n)
            console.log(total)
            /*
            let total = nums.filter(function(n){
               return n < 100;
            }).map(function (n) {
                return n*2;
            }).reduce(function (preValue,n) {
                return preValue+n
            },0)
            */

            /*
            //filter函数的使用
            let newNums = nums.filter(function (n) {
                return n < 100;
            });
            //map函数的使用
            let new2Nums = newNums.map(function (n) {
                return n*2;
            });
            //reduce函数的使用,对数组中所有内容进行汇总,preValue是前一次返回的结果,n数组当前值
            new2Nums.reduce(function (preValue,n) {
                return preValue + n;
            },0)*/

            /*
            //取出小于100的数据
            let newNums = [];
            for (let n of nums){
                if (n < 100){
                    newNums.push(n);
                }
            }
            //需求:将所有小于100的数字进行转化:全部*2
            let new2Nums = [];
            for (let n of newNums){
                new2Nums.push(n*2)
            }
            //需求:将所有小于100的数字相加
            let totalNum = [];
            for (let n of new2Nums){
                totalNum += n;
            }
                */
        script>
    body>
html>
2.2.7v-model数据和表单元素的双向绑定
  • 基本使用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <input type="text" v-model="message">
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   }
            });
        script>
    body>
html>
  • v-model原理
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
             
            
            
            <input type="text" :value="message" @input="valueChange">
            
            <input type="text" :value="message" @input="message = $event.target.value">
            <h2>{{message}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   },
                methods: {
                    valueChange (event) {
                        this.message = event.target.value;
                    }
                }
            });
        script>
    body>
html>
  • v-model结合radio
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <label for="male">
                <input type="radio" id="male" name="sex" value="" v-model="sex" checked>label>
            <label for="female">
                <input type="radio" id="female" name="sex" value="" v-model="sex">label>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld',
                    sex: ''
                   }
            });
        script>
    body>
html>
  • v-model结合checkbox
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <label for="agree">
                <input type="checkbox" id="agree" v-model="isAgree">同意协议
            label>
            <button :disabled="!isAgree">下一步button>
            
            <label>
                <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="rap" v-model="hobbies">rap
            label>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld',
                    isAgree: false,
                    hobbies: []
                   }
            });
        script>
    body>
html>
  • v-model结合select
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <select name="Ve" id="" v-model="fruit">
                <option value="苹果">苹果option>
                <option value="香蕉">香蕉option>
                <option value="榴莲">榴莲option>
                <option value="葡萄">葡萄option>
                <option value="樱桃">樱桃option>
                <option value="山竹">山竹option>
            select>
            
            <select name="Ve" v-model="fruits" 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="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld',
                    fruit: '山竹',
                    fruits: []
                   }
            });
        script>
    body>
html>
  • input值绑定
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <label v-for="item in originHobbies" :for="item">
                <input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
            label>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld',
                    originHobbies: ['唱','跳','rap','篮球']
                   }
            });
        script>
    body>
html>
  • v-model修饰符(常用的)
修饰符 格式 作用
lazy lazy修饰符可以让数据失去焦点或回车才会更新
number number修饰符可以输入框输入的内容自动转化为数字类型
trim 可以过滤内容两边的空格
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <input type="text" v-model.lazy="message"/>
            <h2>{{message}}h2>
            
            <input type="text" v-model.number="age"/>
            <h2>{{age}}----{{typeof age}}h2>
            
            <input type="text" v-model.trim="name">
            <h2>{{name}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld',
                    age: 23,
                    name: '大疆无人机'

                   }
            });
        script>
    body>
html>
2.3计算属性
2.3.1计算属性的入门使用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <h2>{{firstName + ' ' + lastName}}h2>
            <h2>{{firstName}} {{lastName}}h2>
            <h2>{{getFullName()}}h2>
            
            <h2>{{fullName}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    firstName: 'Lebron',
                    lastName: 'James'
                },
                methods: {
                    getFullName: function(){
                        return this.firstName+' '+this.lastName;
                    }
                },
                //computed:计算属性
                computed: {
                    fullName: function(){
                        return this.firstName+ ' ' +this.lastName;
                    }
                }
            });
        script>
    body>
html>
2.3.2赋值操作
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2>{{totalPrice}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    books: [
                        {id: 110, name: 'Unix编程艺术', price: 119},
                        {id: 111, name: '代码大全', price: 105},
                        {id: 112, name: '深入理解计算机原理', price: 98},
                        {id: 113, name: '现代操作系统', price: 87},
                    ]
                },
                computed: {
                    totalPrice: function(){
                        //filter map reduce
                        //return this.books.reduce()
                        let result = 0;
                        for (let i = 0;i < this.books.length;i++){
                            result += this.books[i].price;
                        }
                        return result;
                        /*同上*/
                        /*for (let i in this.books){
                            result += this.books[i].price;
                        }
                        for (let book of this.books){
                            result += book.price
                        }*/
                    }
                }
            });
        script>
    body>
html>
2.3.3计算属性的setter和getter
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <h2>{{fullName}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    firstName: 'Kobe',
                    lastName: 'Bryant'
                   },
                computed: {
                    fullName: function(){
                        return this.firstName+ ' ' +this.lastName;
                    },
                    /* 计算属性的本质实现如下*/
                    /*计算属性一般是没有set方法,只读属性*/
                    fullName: {
                        /*set方法需要传参*/
                      /*set: function(newValue){
                          const names = newValue.split(' ');
                          this.firstName = names[0];
                          this.lastName = names[1];
                      },*/
                      get: function(){
                          return this.firstName+' '+this.lastName;
                      }
                    }
                }
            });
        script>
    body>
html>
2.3.4计算属性和methods的对比
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <h2>{{firstName}} {{lastName}}h2>
            
            <h2>{{getFullName()}}h2>
            <h2>{{getFullName()}}h2>
            <h2>{{getFullName()}}h2>
            <h2>{{getFullName()}}h2>
            
            <h2>{{fullName}}h2>
            <h2>{{fullName}}h2>
            <h2>{{fullName}}h2>
            <h2>{{fullName}}h2>
        div>
        <script src="../js/vue.js">script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    firstName: 'Kobe',
                    lastName: 'Bryant'
                   },
                methods: {
                    getFullName: function () {
                        console.log('getFullName');
                        return this.firstName+ ' '+this.lastName;
                    }
                },
                computed: {
                    fullName: function(){
                        console.log('fullName');
                        return this.firstName+ ' ' +this.lastName;
                    }
                }
            });
        script>
    body>

3.组件化开发

3.1什么是vue.js
  • 它提供了一种抽象,可以开发出一个个独立可复用的小组件来构成我们的应用
  • 任何应用都会被抽象成一颗组件树
3.2注册组件化的基本步骤
  • 创建组件构造器(Vue.extend())
  • 注册组件(Vue.cpmponent())
  • 使用组件
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <my-cpn>my-cpn>
        div>
        <script src="../js/vue.js">script>
        <script>
            //ES6
            /*``支持换行(注意不是单引号)*/
            //创建组件化构造器对象
            const cpnConstructor = Vue.extend({
                template: `
                    

大疆无人机

华为科技

远程通讯无线设备

`
}); //注册组件 Vue.component('my-cpn',cpnConstructor) const app = new Vue({ el: '#app', data: { message: 'HelloWorld' } });
script> body> html>
3.3全局组件和局部组件
  • 基本展示
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            
            <my_cpn>my_cpn>
        div>
        <div id="app2">
           
        div>
        <script src="../js/vue.js">script>
        <script>
            //1.创建组件构造器
            const cpnC = Vue.extend({
                template: `
                    

大疆无人机

华为科技

高端无线通讯

`
}); //注册组件(全局组件) //Vue.component('my-cpn',cpnC); const app = new Vue({ el: '#app', data: { message: 'HelloWorld' }, //局部组件 components: { //my-cpn使用组件时的标签名 my_cpn: cpnC } }); const app2 = new Vue({ el:'#app2', data: { } });
script> body> html>
3.4父子组件
  • 组件组件之间存在层级关系
  • 非常重要的关系就是父子组件
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <cpnc>cpnc>
        div>
        <script src="../js/vue.js">script>
        <script>
            //创建第一个组件构造器(子组件)
            const cpnE = Vue.extend({
                template: `
                    

大疆无人机

华为科技有限公司

高端无线通讯

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

国家电网

达摩院

尖端无线通讯

`
, components: { cpne: cpnE, } }); //root组件 const app = new Vue({ el: '#app', data: { message: 'HelloWorld' }, components: { cpnc: cpnC, } });
script> body> html>
3.5注册组件(语法糖)
  • VUE为了简化这个过程,提供了注册的语法糖
  • 主要是省去了调用**Vue.extends()**的步骤,可以直接使用一个对象来替代
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <cpms>cpms>
            <cpnms>cpnms>
        div>
        <script src="../js/vue.js">script>
        <script>
            //1.全局组件注册构造器
            /*const cpnE = Vue.extend({
                template: `
                    

大疆无人机

全自动通讯检测设备

` });*/
//2.注册组件(全局) //Vue.component('cpnes',cpnE); //使用组件语法糖的写法(全局) Vue.component('cpms',{ template: `

大疆无人机

全自动通讯检测设备

`
}); const app = new Vue({ el: '#app', data: { message: 'HelloWorld' }, //注册局部组件的语法糖 components: { 'cpnms': { template: `

大疆无人机

全自动通讯检测设备

`
} } });
script> body> html>
3.6组件模板分离(script和template标签都能实现)
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <cpn>cpn>
            <cpne>cpne>
        div>
        
        <script type="text/x-handlebars-template" id="cpn">
            <div>
                <h2>大疆无人机</h2>
                <h2>华为科技</h2>
            </div>
        script>
        
        <template id="cpnE">
            <div>
                <h2>国家电网h2>
                <h2>成都航飞集团h2>
            div>
        template>

        <script src="../js/vue.js">script>
        <script>
            //注册全局组件
            Vue.component('cpn',{
                template:  `#cpn`
            });
            Vue.component('cpne',{
                template: `#cpnE`
            })
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   }
            });
        script>
    body>
html>
3.6组件data必须是函数
  • 组件不能直接访问Vue实例中的data
  • 组件对象也是一个data属性(也可以有methods等属性)
  • 只是这个data属性必须是一个函数
  • 函数返回一个对象,对象内部保存着数据
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <template id="cpnE">
        <h2>{{title}}h2>
    template>
    <body>
        <div id="app">
            <cpne>cpne>
        div>
        <script src="../js/vue.js">script>
        <script>
            Vue.component('cpne',{
                template: `#cpnE`,
                data(){
                    return {
                        title: '大疆无人机',
                    }
                }
            });
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   }
            });
        script>
    body>
html>
3.6.1为什么必须是函数
  • 如果不是函数类型,直接是定义变量,在实例化对象的时候,数据共享,组件就是不能独立工作
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <template id="cpn">
        <div>
            <h2>当前计数:{{counter}}h2>
            <button @click="increment">+button>
            <button @click="decrement">-button>
        div>
    template>
    <body>
        
        <div id="app">
            <cpn>cpn>
            <cpn>cpn>
            <cpn>cpn>
        div>
        <script src="../js/vue.js">script>
        <script>
            //注册全局组件
            Vue.component('cpn',{
                template: `#cpn`,
                data(){
                    return{
                        counter: 0,
                    }
                },
                methods: {
                    increment(){
                        this.counter++;
                    },
                    decrement(){
                        this.counter--;
                    }
                }
            });
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   }
            });
        script>
    body>
html>
3.7父子组件通讯

VUE的简单入门_第3张图片

3.7.1父传子
  • props数据验证(支持数据类型)
  • String\Number\Boolean\Array\Object\Date\Function\Symbol
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>

    head>
    <body>
        <template id="cpn">
            <div>
                <p>{{cmovies}}p>
                <h2>{{cmessage}}h2>
            div>
        template>
        <div id="app">
            <cpnc v-bind:cmovies="movies" :cmessage="message">cpnc>
            <cpnC v-bind:cmovies="movies" :cmessage="message">cpnC>
        div>
        <script src="../js/vue.js">script>
        <script>
            const cpnC = {
                template: `#cpn`,
                <!--传值方式-->
                //props: ['cmovies','cmessage'],
                props: {
                   /*//类型限制
                   cmovies: Array,
                   cmessage: String,
                    */
                   //提供一些默认值,设置required为true,必须传值不然报错
                    cmessage: {
                       type: String,
                       default: 'Hello',
                       required: true
                    },
                    //类型事对象或数组时,默认值必须是一个函数
                    cmovies: {
                        type: Array,
                        default: () => ({}),
                        <!--同上-->
                        /*default (){
                            return []
                        }*/
                    },
                    /*
                    //基础的类型检查(`null`匹配任何类型)
                    propA: Number,
                    //多个可能的类型
                    propB: [String,Number],
                    //自定义验证函数
                    propF: {
                        validator: function (value) {
                            //匹配值必须匹配下列字符串中的一个
                            return ['success','warning','danger'].indexOf(value) !== -1
                        }
                    },
                    */
                },
                data(){
                    return{}
                },
                methods: {}
            }
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld',
                    movies: ['大疆无人机','华为科技公司','国家电网','电子科技大学研究史']
                   },
                components: {
                    'cpnc': cpnC,
                    //可以使用增强写法(不使用别名)
                    cpnC,
                }
            });
        script>
    body>
html>
3.7.2props中的驼峰命名(注意事项)
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <template id="cpn">
            <div>
                <h2>{{infos}}h2>
                <h2>{{messageInfoMy}}h2>
            div>
        template>
        <div id="app">
            
            <cpn v-bind:infos="info" :message-info-my="messageInfo">cpn>
        div>
        <script src="../js/vue.js">script>
        <script>
            const cpn = {
                template: `#cpn`,
                props: {
                    infos: {
                        type: Object,
                        default: () => ({}),
                    },
                    messageInfoMy: {
                        type: String,
                        default: ''
                    }
                },
            }
            const app = new Vue({
                el: '#app',
                data: {
                    info: {
                        name: '大疆无人机',
                        age: 5,
                        height: 0.6
                        },
                    messageInfo: '中国成都'
                   },
                components: {
                    cpn
                }
            });
        script>
    body>
html>
3.7.3子传父—自定义事件emit
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        //子组件模板
        <template id="cpn">
            <div>
                <button v-for="item in categories" @click="btnClick(item)">{{item.name}}button>
            div>
        template>
        //父组件模板
        <div id="app">
            //父组件监听(默认把item传递过去)
            <cpn @itemclick="cpnClick">cpn>
        div>
        <script src="../js/vue.js">script>
        <script>
            //子组件
            const cpn = {
                template: `#cpn`,
                data(){
                    return{
                        categories: [
                            {id: '123445', name: '热门推荐'},
                            {id: '123445', name: '手机数码'},
                            {id: '123445', name: '家用家电'},
                            {id: '123445', name: '电脑办公'},
                            {id: '123445', name: '大型电器'},
                            {id: '123445', name: '新款服饰'},
                        ]
                    }
                },
                methods: {
                    btnClick(item){
                        //发射事件:自定义事件
                        this.$emit('itemclick',item);//事件名称,参数
                    }
                }

            }
            //父组件
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   },
                components: {
                    cpn
                },
                methods: {
                   cpnClick(item){
                       console.log('cpnClick',item);
                   }
                }
            });
        script>
    body>
html>
3.7.4父子通讯实现双向绑定
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <cpn :num1="number1" :num2="number2" @nums1="changeNum1" @nums2="changeNum2">cpn>
        div>
        <template id="cpn">
            <div>
                <h2>{{num1}}h2>
                <input type="text" :value = "dnumber1" @input="num1Input"/>
                <h2>{{num2}}h2>
                <input type="text" :value = "dnumber2" @input="num2Input"/>
            div>
        template>
        <script src="../js/vue.js">script>
        <script>
            const cpn = {
                template: `#cpn`,
                props: {
                    num1: Number,
                    num2: Number
                },
                data(){
                    return{
                        dnumber1: this.num1,
                        dnumber2: this.num2
                    }
                },
                methods: {
                    num1Input(event){
                        this.dnumber1 = event.target.value;
                        this.$emit('nums1',this.dnumber1);
                        this.dnumber2 = this.dnumber1*100;
                        this.$emit('nums2',this.dnumber2);
                    },
                    num2Input(event){
                        this.dnumber2 = event.target.value;
                        this.$emit('nums2',this.dnumber2);
                        this.dnumber1 = this.dnumber2/100;
                        this.$emit('nums1',this.dnumber1);
                    }
                },



            }
            const app = new Vue({
                el: '#app',
                data: {
                    number1: 1,
                    number2: 0
                   },
                components: {
                    cpn
                },
                methods: {
                    changeNum1(value){
                        this.number1 = parseInt(value);
                    },
                    changeNum2(value){
                        this.number2 = parseInt(value);
                    }
                }
            });
        script>
    body>
html>
3.7.5父子组件的访问方式:$children
  • 父组件访问子组件:使用$children或$refs
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <cpn ref="abc">cpn>
            <div>
                <button @click="btnClick">按钮button>
            div>
        div>
        <template id="cpn">
            <div>
                我是子组件
            div>
        template>
        <script src="../js/vue.js">script>
        <script>
            const cpn = {
                template: `#cpn`,
                methods: {
                    showMessage(){
                        console.log('showMessage');
                    },
                },
                data(){
                    return{
                        name: '我是子组件的name',
                    }
                }

            }
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   },
                components: {
                    cpn
                },
                methods: {
                    btnClick(){
                        //$children
                        /*console.log(this.$children);
                        console.log(this.$children[0].showMessage());
                        console.log(this.$children[0].name);*/
                        //$refs 对象类型,默认是一个空的对象,ref='abc'
                        console.log(this.$refs.abc.name);

                    }
                }
            });
        script>
    body>
html>
3.7.6子组件访问父组件$parent或$root
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <div id="app">
            <cpn>cpn>
        div>
        <template id="cpn">
            <div>
                <div>我是子组件div>
                <button @click="btnClick">button>
                <ccpn>ccpn>
            div>
        template>
        <template id="ccpn">
            <div>
                <div>我是子子组件div>
                <button @click="btClick">按钮button>
            div>
        template>
        <script src="../js/vue.js">script>
        <script>
            const ccpn = {
                template: `#ccpn`,
                methods: {
                    btClick(){
                        //访问父组件$parent
                        console.log(this.$parent);
                        //访问root组件$root
                        console.log(this.$root.message)
                    }
                }
            };
            const cpn = {
                template: `#cpn`,
                components: {
                    ccpn
                },
                methods: {
                    btnClick(){
                        console.log(this.$parent);
                    }
                }

            }
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   },
                components: {
                    cpn,
                }
            });
        script>
    body>
html>
3.8slot
3.8.1为什么使用slot
  • 组件的插槽也是为了让我们封装的组件更加具备扩展性
  • 插件的基本使用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        
       <div id="app">
           <cpn><button>按钮button>cpn>
           <cpn><span>插槽span>cpn>
           <cpn><em>组件插槽em>cpn>
           <cpn><i>组件插槽i>cpn>
       div>
       <template id="cpn">
           <div>
               <h2>我是组件h2>
               <p>slot插槽的基本使用p>
               
               <slot>slot>
               
               
           div>
       template>
       <script src="../js/vue.js">script>
       <script>
           const cpn = {
               template: `#cpn`
           }
           const app = new Vue({
               el: '#app',
               data: {
                   message: 'HelloWorld'
                  },
               components: {
                   cpn
               }
           });
       script>
    body>
html>
3.8.2具名插槽
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
       <div id="app">
            <cpn><span slot="center">标题span>cpn>
       div>
       <template id="cpn">
           <div>
               <slot name="left"><span>左边span>slot>
               <slot name="center"><span>中间span>slot>
               <slot name="right"><span>右边span>slot>
           div>
       template>
       <script src="../js/vue.js">script>
       <script>
           const cpn = {
               template: `#cpn`
           }
           const app = new Vue({
               el: '#app',
               data: {
                   message: 'HelloWorld'
                  },
               components: {
                   cpn
               }
           });
       script>
    body>
html>
3.8.3编译作用域
  • 父组件模板的所有东西都是在父级作用域内编译子组件模板的所有东西都会在子级作用域内编译
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        
        <div id="app">
            <cpn v-show="isShow">cpn>
        div>
        <template id="cpn">
            <div>
                <h2>我是子组件h2>
            div>
        template>
        <script src="../js/vue.js">script>
        <script>
            const cpn = {
                template: `#cpn`,
                data(){
                    return{
                        isShow: false
                    }
                }
            }
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld',
                    isShow: true
                   },
                components: {
                    cpn
                }
            });
        script>
    body>
html>
3.8.4作用域插槽
  • 父组件替换插槽的标签,但是内容是由子组件来提供
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <template id="cpn">
            <div>
                <slot  :data="pLanguage">
                    <ul>
                        <li v-for="item in pLanguage">{{item}}li>
                    ul>
                slot>
            div>
        template>
        <div id="app">
            
            
            <cpn>
                <template slot-scope="slot">
                    
                    <span>{{slot.data.join(' - ')}}span>
                template>
            cpn>
            <cpn>cpn>
        div>
        <script src="../js/vue.js">script>
        <script>
            const cpn = {
                template: `#cpn`,
                data(){
                    return{
                        pLanguage: ['js','html','css','java','c++','c#']
                    }
                }
            }
            const app = new Vue({
                el: '#app',
                data: {
                    message: 'HelloWorld'
                   },
                components: {
                    cpn
                }
            });
        script>
    body>
html>
3.9模块化开发
3.9.1为什么需要模块化(全局变量名冲突)
./index.html
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        
        <script src="main.js">script>
        <script src="employee1.js">script>
        <script src="employee2.js">script>
        <script src="mmm.js">script>
    body>
html>
./employee1.js
var name = '大疆无人机';
var age = 22;
function sum(num1,num2) {
    return num1+num2;
}
var flag = true;
if (flag){
    console.log(sum(10,20))
}

./mmm.js
if (flag){
    console.log('大疆无人机');
}
./employee2.js
var name = '华为科技';
var flag = false;

console.log(name)
3.9.2早期使用模块化(匿名函数)
  • 直接使用匿名函数,变量\方法只能在局部加载,不能复用代码
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        
        <script src="main.js">script>
        <script src="employee1.js">script>
        <script src="employee2.js">script>
        <script src="mmm.js">script>
    body>
html>
./employee1.js
var moduleA = (function () {
    //导出的对象
    var obj = {}


    var name = '大疆无人机';
    var age = 22;
    function sum(num1,num2) {
        return num1+num2;
    }
    var flag = true;
    if (flag){
        console.log(sum(10,20))
    }

    obj.flag = flag;
    obj.sum = sum;

    return obj;
})()

./mmm.js
(function(){
    //想使用flag
    if (moduleA.flag){
        console.log('大疆无人机');
    }
    //使用sum函数
    console.log(moduleA.sum(20, 30));;
})()
./employee2.js
var moduleB = (function(){
    var name = '华为科技';
    var flag = false;

    console.log(name)
})()
3.9.3常见的模块化规范
  • ConmmonJS 、 AMD 、 CMD,也有ES6的Modules
3.9.4CommonJS模块化(核心导入 导出)
//导出需要导出的变量或方法等
module.exports = {
    //ES6的增强写法(完整的:flag: flag)
    flag,
    sum,
}
//导入
var {flag,sum} = require("./employee1")
3.9.5ES6模块化(export/import) type='module’才支持
./index.html
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script src="es1.js" type="module">script>
        <script src="es2.js" type="module">script>
        <script src="mmm.js" type="module">script>
    body>
html>
./es1.js
var name = '大疆无人机';
var age = 20;
var flag = true;

function sum(num1,num2) {
    return num1+num2;
}
if (flag){
    console.log(sum(23, 27));
}
//导出方式1
export {
    flag,sum
}
//导出方式2
export var number = 1000
export var height = 1.88

//导出函数和类3
export function mul(num1,num2) {
    return num1*num2;
}
export class Person{
    run(){
        console.log("人在奔跑");
    }
}
//导出export default 4   同一个模块只能有一个
const address = '成都市龙泉驿区';
export default address
./mmm.js
//统一全部导入
import * as es from "./es1.js"
console.log(es.mul(19, 20));

//导入的{}中定义的变量
import {flag,sum} from "./es1.js"
if (flag){
    console.log('大疆无人机创新号');
}
console.log(sum(38, 42));

//直接导入export定义的变量
import {number,height} from "./es1.js";
console.log(number);
console.log(height);

//导入export的function
import {mul,Person} from "./es1.js"
console.log(mul(12, 12));
const p = new Person();
p.run();

//导入export default(命名没有强制性,可以自由命名)
import add from "./es1.js";
console.log(add);
./es2.js
import {sum} from './es1.js';
var name = '华为科技';
var flag = false;

console.log(name);
console.log(sum(100, 200));

4.webpack

4.1认识webpack
  • webpack是一个现代的js应用的静态模块打包工具
  • AMD \CMD \CommonJS\ES6转化为浏览器识别的,并且自动配置相关依赖
4.2webpack的安装
  • webpack正常运行依赖node环境,node环境为了可以正常执行很多代码,必须其中包含各种依赖包npm工具
  • 安装webpack首先需要安装nodejsnodejs自带软件包管理工具npm
#查看版本
node -v
#安装全局的webpack
npm install webpack@版本 -g       ##可以指定版本
npm install webpack-cli@版本 -g
#局部安装webpack
##在终端直接执行webpack命令,使用的全局安装的webpack
##在package.json中定义script时,其中包含了webpack命令,那么使用的是局部webpack
cd 对应项目(目录)
npm install webpack@版本 --save-dev
4.3webpack起步
4.3.1webpack打包出现问题
  • 故障描述
Hash: 85eaf324cafc844c2402
Version: webpack 4.41.6
Time: 110ms
Built at: 2020-04-28 11:34:13
 1 asset
Entrypoint main = main.js
[0] multi ./src/main.js ./dist/bundle.js 40 bytes {0} [built]
[1] ./src/main.js 97 bytes {0} [built]
[2] ./src/mathUtil.js 160 bytes {0} [built]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'dev
elopment' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mod
e/

ERROR in multi ./src/main.js ./dist/bundle.js
Module not found: Error: Can't resolve './dist/bundle.js' in 'E:\webcode\vue\webpack\webpack基本使用'
 @ multi ./src/main.js ./dist/bundle.js main[1]
4.3.2处理方案
  • 方式1
    • 查看导入的模块引入路径是否有问题
  • 方式2
    查看当前webpack版本,webpack高版本使用的是(打包指令)
    webpack ./src/main.js -o ./dist/dunble.js
    
4.4webpack的基本使用
./info
export const name = '大疆无人机';
export const age = 18;
export const height = 1.88;



./mathUtil.js
function mul(num1,num2) {
    return num1*num2;
}
function sum(num1,num2) {
    return num1+num2;
}

//commonJS
module.exports = {
    sum,
    mul
}
./main.js
//使用commonJS
const {sum,mul} = require('./mathUtil.js');
console.log(sum(20, 30));
console.log(mul(20, 40));
//使用ES6的模块化的规范
import {name,age, height} from "./info";
console.log(name);
console.log(age);
console.log(height);
##打包
webpack ./src/main.js -o ./dist/dunble.js
./index.html
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script src="./dist/bundle.js">script>
    body>
html>
4.5webpack的配置
4.5.1创建webpack.config.js
./webpack.config.js
const path = require('path')
module.exports = {
    /*入口*/
    entry: './src/main.js',
    /*出口 path必须是绝对路径,npm init之后,_dirname是上下文获取路径,'dist'是拼接路径*/
    output: {
        path: path.resolve(_dirname,'dist'),
        filename: 'bundle.js'
    }
}
##npm初始化,自动创建package.json
npm init

###"license": "ISC"   是否开源
./package.json
{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.43.0"
  }
}
##打包方式
webpack ./src/main.js -o ./dist/dunble.js
##使用webpack直接打包
###建立webpack.config.js配置其内容
webpack  -------打包
###需要在package.json配置
"build": "webpack"
npm run build ------打包
##webpack在终端直接使用全局webpack,全局webpack版本获取与开发webpack版本不同
###安装局部webpack(在项目目录下)
npm install webpack@版本 --save-dev
###安装局部webpack之后,执行npm run build执行的webpack最先是执行局部webpack
###如果不配置script脚本 "build": "webpack",需要通过如下方式启动webpack打包
node_modules/.bin/webpack
4.5.2loader的使用(https://www.webpackjs.com/)
##webpack本身不支持css、图片等转化
###对webpack扩展loader
####安装loader---css
npm install --save-dev css-loader
npm install style-loader --save-dev 
####在webpack.config.js中的module关键字下进行配置(程序入口也需要引入css文件)
module: {
    rules: [
        {
            test: /\.css$/,
            use: ['style-loader','css-loader']
        }
    ]
}

####安装loader---less-loader
npm install --save-dev less-loader less ---------less-loader加载,less转化
####在webpack.config.js中的module关键字下进行配置(程序入口也需要引入less文件)
{
    test: /\.less$/,
    use: [
        {
            loader: "style-loader"
        },{
            loader: "css-loader"
        },{
            loader: "less-loader"
        }
    ]
}

####安装loader----url-loader
npm install --save-dev url-loader
####在webpack.config.js中的module关键字下进行配置(程序入口也需要引入less文件)
{
    test: /\.(png|jpg|gif)$/,
    use: {
        loader: 'url-loader',
        options: {
            /*当加载的图片,小于limit时,会将图片编译成base64字符串形式;
            大于limit时,需要时使用file-loader,安装file-loader即可 npm install file-loader --save-dev
            不需要配置file-loader,打包时,把文件重新打包到dist,注意文件路径
            */
            limit: 8192,
            /*打包之后,对文件命名处理*/
            name: 'img/[name]-[hash:8].[ext]'
        }
    }
}

####安装loader---babel-loader
npm install --save-dev babel-loader@版本 babel-core babel-preset-es2015
####在webpack.config.js中的module关键字下进行配置(依赖于webpack),将ES6转化为ES5
{
    test: /\.js$/,
    exclude: /(node_modules|bower_components)/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['es2015']
        }
    }
}
4.5.3webpack中的配置VUE
##安装Vue
npm install vue --save
##使用Vue
import Vue from 'vue'
##直接打包(生成如下两个版本)
npm run build
###runtime-only---->代码中,不可以有任何的template,默认
###runtime-compiler---->代码中,可以有template,因为有compiler可以编译template
####指定runtime-compiler,在webpack.config.js中配置
resolve: {
    /*在导入组件时,如果想省略后缀名,可以只用这个*/
    extensions: ['.js','.vue','.css'],
    
    alias: {
        'vue$': 'vue/dist/vue.esm.js'
    }
}
4.5.4el与template区别
  • vue在编译的时候,template模板的内容会被替换到el定位标签里面
##安装loader------vue
npm install vue-loader vue-template-complier --save-dev
##修改webpack.config.js的配置文件
{
    test: /\.vue$/,
    use: {
        loader: 'vue-loader'
    }
}
###打包可能会出现error 提示缺少corresponding plugin,loa-loader版本过高的问题,可以直接
###在package.json中降低版本,执行npm install重新加载("^"符号是取区间版本,当前指定版本,如果不存在向后移,且不会超过大版本)
4.5.5plugin的使用
#plugin是什么
##plugin是插件的意思,通常是用于对某个现有的架构进行扩展
##webpack插件中的插件,就是对webpack现有功能的各种扩展
#loader和plugin区别
##loader主要用于转换某些类型的模块,他是一个转换器
##plugin是插件,他又对webpack本身的扩展,是一个扩展器
#plugin的使用过程
##通过npm安装需要使用的plugin
##在webpack.config.js中的plugin中配置插件
##添加版权的plugin(webpack自带的)
const webpack = require('webpack)
plugins: [
    new webpack.BannerPlugin('版权声明概述')
]

##打包html的plugin
###安装
npm install html-webpack-plugin --save-dev
###在webpack.config.js中的plugin中配置插件
const path = require('path')
plugins: {
    new HtmlWebpackPlugin({
        /*根据index.html模板生成*/
        template: 'index.html'
    }),
}

##js压缩的plugin(版权声明就会被删除,开发阶段不推荐使用,不好调试)
###安装
npm install uglifyjs-webpack-plugin@版本 --save-dev
###在webpack.config.js中的plugin中配置插件
const uglifyJsPlugin = require('uglifyjs-webpack-plugin')
plugins: {
    new HtmlWebpackPlugin({
        /*根据index.html模板生成*/
        template: 'index.html'
    }),
    new uglifyJsPlugin()
}
4.6搭建本地服务器(开发时使用)
4.6.1搭建本地服务器,在开发时,修改或开发,不需要重写打包
##安装
npm install --save-dev webpack-dev-server@版本
##在webpack.config.js中的devserver配置参数
devServer: {
    contentBase: './dist',
    /*是否实时监听*/
    inline:true
}

###contentBase:为那个文件夹提供本地服务,默认是根文件夹
###port:指定端口
###inline:页面实时刷新
###historyApiFallback:SPA页面中,依赖HTML5的history模式
##本地服务启动(类似于启动tomcat)
###配置package.json脚本
"dev": "webpack-dev-server"
###启动后,自动在浏览器加载
"dev": "webpack-dev-server --open"
###启动
npm run dev
4.6.2webpack配置文件分离
##安装
npm install webpack-merge --save-dev
##将配置文件分离base.config.js prod.config.js dev.config.js,可以建立一个专门的配置文件夹build
###base.config为公共配置文件,注意打包之后的路径问题(output参数),prod.config.js生成环境配置文件,dev.config.js开发环境配置文件
###在配置文件中导入相关配置即可
eg:生产环境
const uglifyJsPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base-config')
 module.exports = webpackMerge(baseConfig,{
     plugins: [
         new uglifyJsPlugin()
     ]
 })
 ###配置package.json
 "scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "build": "webpack --config ./build/prod.config.js",
  "dev": "webpack-dev-server --config ./build/dev.config.js"
},

5.Vue Cli详解

5.1什么是Vue Cli
  • Vue.js开发大型应用时,需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等
  • CLI是Command-Line-Iterface,翻译为命令行界面,但是俗称脚手架
  • Vue CLI是一个官方发布的vue.js脚手架
  • 使用vue-cli可以快速搭建Vue开发环境以及对应的webpack配置
5.2Vue Cli使用前提 -------->node webpack
#npm管理工具
#国内使用npm官方的镜像可能会很慢的,可以使用淘宝的npm镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
##安装好之后就可以使用cnpm命令
5.3安装Vue脚手架
##查看当前版本
vue --version
##更新版本,需要先卸载之前版本
npm uninstall vue-cli -g
##安装脚手架
npm install -g @vue/cli
5.4脚手架初始化项目
##脚手架3及3及以上的版本初始化项目
vue create 项目名称
##若想使用脚手架2.x的版本创建项目,首先需要安装旧的模板
npm install -g @vue/cli-init
###2.x版本初始化项目
vue init webpack 项目名称
5.5Vue Cli2初始化项目详解

VUE的简单入门_第4张图片
VUE的简单入门_第5张图片

5.6ESLint规范
  • 使用ESLint,要注意编码样式,如不加分号、方法名空格等
  • 一般创建项目时导入ESLint规范,但是在实际开发过程中不适用
./config/index.js
useESLint:false

6.Vue基础语法

6.1runtime-compiler与runtime-only区别

VUE的简单入门_第6张图片
VUE的简单入门_第7张图片

  • runtime-only性能更好
  • runtime-compiler代码量大,runtime-only代码量少
6.2createElement函数
  • render函数,返回的createElement(‘标签’,{标签属性},[‘’]),会覆盖el指定标签
new Vue({
  el: '#app',
  /*components: { App },
  template: ''*/
  render: function (createElement){
    // //普通用法
    // return createElement('h2',{class:'box'},['hello world'])
    //组件对象
    return createElement(App)
  }
})
6.3npm run build与npm run dev区别

VUE的简单入门_第8张图片
VUE的简单入门_第9张图片

6.4vue-cli3与2区别
  • vue-cli3基于webpack4打造的,vue-cli2基于webpack3
  • vue-cli3的设计原则是"0配置*",移除的配置文件根目录下的build和config等目录
  • vue-cli3提供了vue ui命令,提供可视化配置,更加人性化
  • 移除了static文件夹,新增public文件夹,并且index.html移动到public中
6.5Vue-Cli3创建项目
##Cli3
vue create 项目名
##运行项目
npm run serve
6.5.1Cli3初始化项目详解
  • 地址 https://www.jianshu.com/p/c7df292915e7
    VUE的简单入门_第10张图片
6.5.2Cli3配置文件修改
  • 方式1
vue ui
##导入项目,就可以看到相关配置
  • 方式2
##在项目根目录创建vue.config.js
##把需要的配置设置好,项目会自动合并

VUE的简单入门_第11张图片

6.6补充点ES6
6.6.1ES6箭头函数
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>
            //箭头函数:也是一种定义函数的方式
            //定义函数的方式:function
            const aaaa = function(){

            }
            //对象字面量中定义函数
            const obj = {
                bbb: function(){

                },
                ccc(){
                    
                }
            }
            //ES6箭头函数
            const eee = (参数列表) => {
                
            }
        script>
    body>
html>
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>
            //参数问题
            //1.1放两个参数
            const sum = (num1,num2) =>{
                return num1+num2;
            }
            //1.2放入一个参数,可以省略()
            const power = num =>{
                return num * num;
            }
            //函数中
            //2.1函数代码块中有多行代码时
            const test = () => {
                //1.打印hello world
                console.log('hello world');
                //2.打印Hello Vue
                console.log('Hello Vue');
            }
            //2.2函数代码块中只有一行代码
            const mul = (num1,num2) => num1 * num2;
        script>
    body>
html>
6.6.2this的使用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>

            setTimeout(function(){
                console.log(this);//window
            },1000)
            setTimeout(() => {
                console.log(this);//window
            },1000)
            //结论:箭头函数中的this是如何查找的?
            //A:向外层作用域中,一层层查找this,直到有this的定义
            const obj = {
                aaa(){
                    setTimeout(function () {
                        console.log(this);//window
                    },1000)
                    setTimeout(()=>{
                        console.log(this);//obj对象
                    },1000)
                }
            }
            obj.aaa();

            const obj = {
                aaa(){
                    setTimeout(function () {
                        console.log(this);//window
                        setTimeout(function () {
                            console.log(this);//window
                        },1000)
                    },1000)
                    setTimeout(()=>{
                        console.log(this);//window
                    },1000)
                    setTimeout(()=>{
                        console.log(this);//obj对象
                        setTimeout(function () {
                            console.log(this);//window
                        },1000)
                        setTimeout(()=>{
                            console.log(this);//obj对象
                        },1000)
                    },1000)
                }
            }
        script>
    body>
html>
6.6.3Promise使用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>
            //1.使用setTimeout
            setTimeout(() => {
                console.log('大疆无人机');
            },1000);
            //参数本身就是函数,函数还有两个参数
            //resolve reject本身他们又是函数
            //链式编程
            /*new Promise((resolve,reject) => {
                //第一次网络请求
                setTimeout(() => {
                    resolve()
                },1000)
            }).then(() => {
                //第一次拿到结果的处理代码
                console.log('大疆无人机');
                console.log('大疆无人机');
                console.log('大疆无人机');
                console.log('大疆无人机');
                console.log('大疆无人机');
                return new Promise((resolve,reject) => {
                    //第二次网络请求
                    setTimeout(() => {
                        resolve()
                    },1000)
                })
            }).then(() => {
                //第二次拿到结果的处理代码
                console.log('华为科技');
                console.log('华为科技');
                console.log('华为科技');
                console.log('华为科技');
                console.log('华为科技');
                return new Promise((resolve, reject) => {
                    //第三次网络请求
                    setTimeout(() => {
                        resolve()
                    },1000)
                })
            }).then(() => {
                //第三次拿到结果的处理代码
                console.log('中星科技');
                console.log('中星科技');
                console.log('中星科技');
                console.log('中星科技');
                console.log('中星科技');
            })*/
                /*setTimeout(() => {
                    console.log('大疆无人机');
                    console.log('大疆无人机');
                    console.log('大疆无人机');
                    console.log('大疆无人机');
                    console.log('大疆无人机');
                    setTimeout(() => {
                        console.log('华为科技');
                        console.log('华为科技');
                        console.log('华为科技');
                        console.log('华为科技');
                        console.log('华为科技');
                        setTimeout(() => {
                            console.log('中星科技');
                            console.log('中星科技');
                            console.log('中星科技');
                            console.log('中星科技');
                            console.log('中星科技');
                        },1000);
                    },1000);
                },1000);

            })*/

            //什么情况下使用Promise?
            //一般情况下是有异步操作时,使用promise进行封装
            //new  -> 构造函数(1.保存一些状态信息,2.执行传入函数)
            //在执行我们传入的回调函数时,会传入两个参数,resolve reject,本身又是函数
            new Promise((resolve, reject) => {
                setTimeout(() => {
                    //成功的时候调用resolve
                    //resolve回调函数,将参数传入then里面的函数
                    resolve('str');
                    //失败的时候调用reject
                    reject('error message')
                },1000)
            }).then((data) => {
                //处理代码
                console.log(data);//str
                console.log(data);//str
                console.log(data);//str

            }).catch((err) => {
                //处理代码
                console.log(err);//error message
                console.log(err);//error message
                console.log(err);//error message
            })
        script>
    body>
html>
  • Promise的三种状态
    • 异步操作之后会有三种状态
      VUE的简单入门_第12张图片
  • pending:等待状态,比如正在进行网络请求,或者定时器没有到时间
  • fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
  • reject:解决状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()

DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>
            new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve('大疆无人机');
                    reject('error message')
                },1000)
            }).then((data) => {
                console.log(data);
            },(error) => {
                console.log(error);
            })
        script>
    body>
html>
  • Promise链式调用
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>title>
    head>
    <body>
        <script>
           /* 网络请求: aaa---->自己处理10行(模拟)
            处理: aaa111----->自己处理10行(模拟)
            处理:aaa111222--->自己处理10行(模拟)*/
          /*new Promise((resolve, reject) => {
              setTimeout(() => {
                  resolve('aaa')
              },1000)
          }).then((res) => {
              //1.处理代码
              console.log(res,'第一层处理的结果');
              return new Promise((resolve, reject) => {
                  //对结果进行处理
                  //resolve(res+'111')
                  reject('error message')
              })
          }).then((res) => {
            console.log(res, '第二层的10行处理代码');
            return new Promise((resolve, reject) => {
                resolve(res+'222');
            })
          }).then((res) => {
              console.log(res,'第三层的10行处理代码');
          }).catch((err) => {
              console.log(err);
          })*/
         /* new Promise((resolve, reject) => {
              setTimeout(() => {
                  resolve('aaa')
              },1000)
          }).then((res) => {
              //1.处理代码
              console.log(res,'第一层处理的结果');
              return Promise.resolve(res+'111');
          }).then((res) => {
            console.log(res, '第二层的10行处理代码');
            return Promise.resolve(res+'222')
          }).then((res) => {
              console.log(res,'第三层的10行处理代码');
          })*/
           //省略Promise.resolve
           /*new Promise((resolve, reject) => {
               setTimeout(() => {
                   resolve('aaa')
               },1000)
           }).then((res) => {
               //1.处理代码
               console.log(res,'第一层处理的结果');
               return res+'111';
           }).then((res) => {
               console.log(res, '第二层的10行处理代码');
               return res+'222';
           }).then((res) => {
               console.log(res,'第三层的10行处理代码');
           })*/
            new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve('aaa')
                },1000)
            }).then((res) => {
                //1.处理代码
                console.log(res,'第一层处理的结果');
                //return Promise.resolve(res+'111');
                //return Promise.reject('error message');//同下
                throw 'error message'
            }).then((res) => {
                console.log(res, '第二层的10行处理代码');
                return Promise.resolve(res+'222')
            }).then((res) => {
                console.log(res,'第三层的10行处理代码');
            }).catch((err) => {
                console.log(err);
            })
        script>
    body>
html>
  • Pomise的all方法
DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <script>
            Promise.all([
                new Promise((resolve, reject) => {
                    $.ajax({
                        url: 'url1',
                        success: function(data){
                            resolve(data)
                        }
                    })
                }),
                new Promise((resolve, reject) => {
                    $.ajax({
                        url: 'url2',
                        success: function(data){
                            resolve(data)
                        }
                    })
                })
            ]).then(results => {
                console.log(results[0]);
                console.log(results[1]);
            })
        script>
    body>
html>

6.6.7vite创建vue3
1.初始化
npm init vite@latest

//yarn
yarn create vite

7.Vue-router

7.1认识路由
  • 路由表----->路由表本质就是一个映射表,决定了数据包的指向
  • 前端渲染
    • 在静态页面服务器上加载url对应的页面,发送到浏览器进行展示
  • 后端渲染
    • 后端处理url与页面之间的映射关系
      VUE的简单入门_第13张图片
7.2url的hash和html5的history
##监听url的变化,网页不刷新
localhost.hash = 'foo'

##监听url变化,网页不刷新
history.pushState({},'','foo'})
##history通过栈的方式放入,退回上一层
history.back()

##监听url变化,网页不刷新(直接替换,不保留)
history.replaceState({},'','foo')

##监听url变化,网页不刷新(栈方式放入,网页直接定位)
history.go(-1);  //等于history.back()
history.forward();//等于history.go(1)
7.3目前前端流行的三大框架,都有自己的路由实现
  • Angular的AngRouter
  • React的ReactRouter
  • Vue的vue-router
7.3.1vue-router
  • vue-router是vue.js官方路由插件,它和vue.js是深度集成哪个,适合用于构建单页面应用 地址:vue-router
7.3.2vue-router是基于路由和组件的
  • 路由用于设定访问路径,将路径组件映射起来
  • vue-router的单页面应用中,页面的路径的改变就是组件的切换
7.3.3安装vue-router
npm install vue-router --save
7.3.4使用vue-router,来配置路由路径
  • 导入路由对象,并且调用Vue.use(VueRouter)
  • 创建路由实例,并且传入路由映射配置
  • 在Vue实例中挂在创建的路由实例
7.3.5使用vue-router
  • 创建路由组件
./Home.vue
<template>
  <div>
    <h2>我是首页</h2>
    <p>我是首页信息展示页面</p>
  </div>
</template>

<script>
    export default {
        name: "Home"
    }
</script>

<style scoped>

</style>

./About.vue
<template>
  <div>
    <h2>我是关于页面</h2>
    <p>展示用户个人信息及其相关的其他信息</p>
  </div>
</template>

<script>
    export default {
        name: "About"
    }
</script>

<style scoped>

</style>
  • 配置路由映射:组件和路由映射关系
//配置路由相关的信息
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/Home'
import About from "../components/About";

//通过Vue.use(插件),安装插件
Vue.use(Router)
//创建路由对象
export default new Router({
  //配置路由和组件之间的应用关系
  routes: [
    {
      path: '/home',
      name: 'Home',
      component: Home
    },
    {
     path: '/about',
      name: 'About',
      component: About
    }
  ]
})
  • 使用路由:通过
<template>
  <div id="app">
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>

</style>
7.4vue-router基本使用
7.4.1路由的默认路径(网页打开显示的首页)
export default new Router({
  //配置路由和组件之间的应用关系
  routes: [
    {
      path: '',
      //redirect重定向
      redirect: '/home'
    }
}
7.4.2改变路由的方式有两种(URL路径是否显示#,如果不希望显示#,就使用history)
  • URLhash

  • HTML5history

  • 默认情况下,路径的改变使用URL的hash

  • 方式1

export default new Router({
  routes: [
    //配置路由和组件之间的应用关系
    {
      path: '',
      //redirect重定向
      redirect: '/home',
    },
    {
      path: '/home',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ],
  mode: 'history'
})

-方式2

const routes = [ 
    {
    path: '',
    //redirect重定向
    redirect: '/home',
  },
  {
    path: '/home',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
] 
const router = new Router({
  routes,
  mode: 'history'
})
export default router
7.4.3router-link补充
<router-link>,使用属性to,用于指定跳转的路径
<router-link>还有一些其他属性
    tag:tag可以指定<router-link>之后渲染成什么组件,如<router-link to='/home' tag='button'>
    replace:使用replace属性,可以取消pushState具有的特性<router-link to='/home' replace>
    active-class:修改原本自带的属性值(router-link-active),<router-link active-class='active'>
    
####router-link中修改class属性值比较麻烦,可以直接在路由的index.js里面添加一个linkActiveClass: 'active'   
7.4.4路由跳转
<template>
   <div>
   //方式1
    <!--<router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>-->
    //方式2
    <button @click="homeClick">首页</button>
    <button @click="aboutClick">关于</button>
    //渲染占位
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods: {
    //通过代码的方式修改路由vue-router
    //push==>pushState
    homeClick(){
      // this.$router.push("/home")
      this.$router.replace("/home")
    },
    aboutClick(){
      // this.$router.push("/about")
      this.$router.replace("/about")
    }
  }
}
</script>

<style>

</style>
7.4.5动态路由
./User.vue
<template>
    <div>
      <h2>我是用户界面</h2>
      <p>我来展示用户的详细信息</p>
      <h2>{{userId}}</h2>
      //同上
      <h2>{{$route.params.userId}}</h2>
    </div>
</template>

<script>
    export default {
        name: "User",
        computed: {
          userId(){
            //哪一个活跃就是$route
            return this.$route.params.userId
          }
        }
    }
</script>

<style scoped>

</style>

./index.js
//配置路由相关的信息
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/Home'
import About from "../components/About";
import User from "../components/User";

//通过Vue.use(插件),安装插件
Vue.use(Router)
//创建路由对象
//const routes = [
export default new Router({
  routes: [
    //配置路由和组件之间的应用关系
    {
      path: '',
      //redirect重定向
      redirect: '/home',
    },
    {
      path: '/home',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    },
    {
      path: '/user/:userId',
      name: 'User',
      component: User
    }
  ],
  mode: 'history',
  linkActiveClass: 'active'
})

//]
/*const router = new Router({
  routes,
  mode: 'history'
})
export default router*/

./App.vue
<template>
  <div id="app">
    <router-link to="/home">首页</router-link>
    <router-link :to="'/user/'+userId">用户</router-link>
    <router-link to="/about">关于</router-link>
    <!--<button @click="homeClick">首页</button>
    <button @click="aboutClick">关于</button>-->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  data(){
    return{
      userId: '大疆无人机'
    }
  },
  /*methods: {
    //通过代码的方式修改路由vue-router
    //push==>pushState
    homeClick(){
      // this.$router.push("/home")
      this.$router.replace("/home")
    },
    aboutClick(){
      // this.$router.push("/about")
      this.$router.replace("/about")
    }
  }*/
}
</script>

<style>

</style>
7.4.6路由的懒加载
  • 项目构建,打包js比较大时,浏览器在访问时,会影响用户体验,推荐使用懒加载,来实现业务分模块化,在服务器中请求
##懒加载
###方式一:结合Vue的异步组件和webpack的代码分析
const Home = resolve => {require.ensure(['../components/Home.vue'],() => {resolve(_require('../components/Home.vue'))})}
###方式二:AMD写法
const About = resolve => _require(['../components/About.vue'],resolve)
###方式三:ES6中,我们可以有更加简单的写法来组织Vue异步组件和webpack的代码分割
const Home = () => import('../components/Home.vue')
//配置路由相关的信息
import Vue from 'vue'
import Router from 'vue-router'

// import Home from '../components/Home'
// import About from "../components/About";
// import User from "../components/User";

const Home = () => import('../components/Home');
const About = () => import('../components/About');
const User = () => import('../components/User')

//通过Vue.use(插件),安装插件
Vue.use(Router)
//创建路由对象
//const routes = [
export default new Router({
  routes: [
    //配置路由和组件之间的应用关系
    {
      path: '',
      //redirect重定向
      redirect: '/home',
    },
    {
      path: '/home',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    },
    {
      path: '/user/:userId',
      name: 'User',
      component: User
    }
  ],
  mode: 'history',
  linkActiveClass: 'active'
})

//]
/*const router = new Router({
  routes,
  mode: 'history'
})
export default router*/
7.4.7vue-router嵌套路由

VUE的简单入门_第14张图片

./HomeNews.vue
<template>
  <div>
    <ul>
      <li>新闻1</li>
      <li>新闻2</li>
      <li>新闻3</li>
      <li>新闻4</li>
    </ul>
  </div>
</template>

<script>
    export default {
        name: "HomeNews"
    }
</script>

<style scoped>

</style>
./HomeMessage
<template>
  <div>
    <ol>
      <li>消息展示栏1</li>
      <li>消息展示栏2</li>
      <li>消息展示栏3</li>
      <li>消息展示栏4</li>
    </ol>
  </div>
</template>

<script>
    export default {
        name: "HomeMessage"
    }
</script>

<style scoped>

</style>

./Home.vue
<template>
  <div>
    <h2>我是首页</h2>
    <p>我是首页信息展示页面</p>
    <router-link to="/home/news">新闻</router-link>
    <router-link to="/home/message">消息</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
    export default {
        name: "Home"
    }
</script>

<style scoped>

</style>
./index.js   router
//配置路由相关的信息
import Vue from 'vue'
import Router from 'vue-router'

// import Home from '../components/Home'
// import About from "../components/About";
// import User from "../components/User";

const Home = () => import('../components/Home');
const HomeNews = () => import('../components/HomeNews');
const HomeMessage = () => import('../components/HomeMessage')
const About = () => import('../components/About');
const User = () => import('../components/User')

//通过Vue.use(插件),安装插件
Vue.use(Router)
//创建路由对象
//const routes = [
export default new Router({
  routes: [
    //配置路由和组件之间的应用关系
    {
      path: '',
      //redirect重定向
      redirect: '/home',
    },
    {
      path: '/home',
      name: 'Home',
      component: Home,
      children: [
        {
          path: '',
          redirect: 'news'
        },
        {
          path: 'news',
          name: 'HomeNews',
          component: HomeNews

        },
        {
          path: 'message',
          name: 'HomeMessage',
          component: HomeMessage
        }
      ]
    },
    {
      path: '/about',
      name: 'About',
      component: About
    },
    {
      path: '/user/:userId',
      name: 'User',
      component: User
    }
  ],
  mode: 'history',
  linkActiveClass: 'active'
})

//]
/*const router = new Router({
  routes,
  mode: 'history'
})
export default router*/
7.4.8vue-router参数传递(URL:协议://主机/路径?查询)
  • 传递参数主要有两种类型 paramsquery
  • 方式1—params
//params类型
配置路由方式:/router/:id
{
  path: '/user/:userId',
  name: 'User',
  component: User
}
传递方式:在path后面跟上对应的值
/方式1:
 <router-link :to="'/user/'+userId">用户</router-link>
    <router-link to="/about">关于</router-link>
    <!--<button @click="homeClick">首页</button>
    <button @click="aboutClick">关于</button>-->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  data(){
    return{
      userId: '大疆无人机'
    }
  },
/方式2:
<button @click="userClick">用户</button>
userClick(){
  this.$router.push("/user"+this.userId)
},
///传递后形成的路径:/router/123,/router/abc
 <h2>{{userId}}</h2>
      //同上
      <h2>{{$route.params.userId}}</h2>
    </div>
</template>

<script>
    export default {
        name: "User",
        computed: {
          userId(){
            //哪一个活跃就是$route
            return this.$route.params.userId
          }
        }
    }
  • 方式2—query
//query的类型
///配置路由格式/router,也就是普通配置
{
  path: '/profile',
  name: 'Profile',
  component: Profile
}
///传递方式:对象中使用query的key作为传递方式
/方式1:
<router-link :to="{path: '/profile',query: {name: '大疆无人机',age: 4,height: 1.8}}">档案</router-link>
方式2:
<button @click="profileClick">档案</button>    
profileClick(){
  this.$router.push({
    path: '/profile',
    query: {
      name: '华为科技',
      age: 4,
      height: 1.88
    }
  })
}
传递后形成的路径:/router?id=123,/router?id=abc
<template>
    <div>
      <h2>我是Profile页面</h2>
      <p>{{$route.query.name}}</p>
      <p>{{$route.query.age}}</p>
      <p>{{$route.query.height}}</p>
    </div>
</template>

<script>
    export default {
        name: "Profile"
    }
</script>

<style scoped>

</style>
7.4.9$router和$route由来(所有组件都继承vue原型)
  • $router对象:Router---->index.js------>router.d.ts,router.d.ts里面就可以看到很多方法push、replace等
  • $route对象当前处于活跃的路由
7.5vue-router导航守卫
  • 问题:浏览器导航栏标识随网页跳转而修改(浏览器导航栏名称)(全局守卫)
7.5.1解决方案1

VUE的简单入门_第15张图片

./Home.vue
<script>
    export default {
        name: "Home",
        data(){
          return {
            message: '你好啊'
          }
        },
        created() {
          console.log('created');
          document.title = '首页'

        },
        mounted() {
          console.log('mounted')
        },
        updated() {
          console.log('updated')
        }
    }
</script>
7.5.2解决方案2
{
  path: '/home',
  name: 'Home',
  component: Home,
  meta: {
    title: '首页'
  },
  children: [
    {
      path: '',
      redirect: 'news'
    },
    {
      path: 'news',
      name: 'HomeNews',
      component: HomeNews

    },
    {
      path: 'message',
      name: 'HomeMessage',
      component: HomeMessage
    }

  ]
},


//Router对象
//前置钩子(hook)
router.beforeEach((to ,from ,next) =>{
  //从from跳转到to
  document.title = to.matched[0].meta.title
  next();
})


//后置钩子(hook)
router.afterEach((to ,from) => {
    //不需要主动调用next函数
})
7.5.3组件内的守卫

VUE的简单入门_第16张图片

7.5.4keep-alive遇到vue-router
  • router-view也是一个组件,如果直接被包含在keep-alive里面,所有路径匹配到的视图组件都会被缓存
  • keep-alive主要是使组件不要被频繁的销毁和创建,保留组件状态
  • 其中包含两个属性
    • include —字符串或正则表达式,只有匹配的组件会缓存
    • exclude --字符串或正则表达式,任何匹配的组件都不会被缓存
//活跃函数和非活跃函数,只有该组件被保持了状态使用keep-alive时,才有效的
activated() {
  //活跃
  this.$router.push(this.path)
},
deactivated() {
    //非活跃的
},
//组件守卫
beforeRouteLeave(to, from, next){
  this.path = this.$router.path
  next()
}
//不会缓存的组件,Profile是组件的name,多个可以直接使用逗号隔开
<keep-alive exclude="Profile">
  <router-view></router-view>
</keep-alive>
7.6项目开发中资源引入路径问题

<tab-bar-item path="/home" activeColor="blue">
  <img slot="item-icon" src="../assets/img/tabbar/0506.jpg" alt="">
  <img slot="item-icon-active" src="../assets/img/tabbar/0406.jpg" alt="">
  <div slot="item-text">首页div>
tab-bar-item>


./build/webpack.base.conf.js
resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
    '@': resolve('src'),
    'assets': resolve('src/assets'),
    'components': resolve('src/components'),
    'views': resolve('src/views'),
  }
},

<tab-bar-item path="/home" activeColor="blue">
  <img slot="item-icon" src="~assets/img/tabbar/0506.jpg" alt="">
  <img slot="item-icon-active" src="~assets/img/tabbar/0406.jpg" alt="">
  <div slot="item-text">首页div>
tab-bar-item>

6.Vuex详解

6.1概述
  • Vuex是一个专为Vue.js应用程序开发的状态管理模式
  • 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
  • Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-tavel调试、状态快照导入导出等高级调试工具
  • 状态管理到底是什么?
    • 状态管理模式集中式存储管理这些名词听起来不易理解
    • 简单的将其看成需要多个组件共享变量全部存储在一个对象里面
    • 这个对象放在顶层的Vue实例中,让其他组件可以使用
6.2单界面的状态管理

VUE的简单入门_第17张图片

  • State:状态,简单比喻为data
  • View:视图层,可以针对State的变化,显示不同的信息
  • Actions:用户的各种操作:点击、输入等,会导致状态的变化
6.3安装Vuex
  • 安装
npm install vuex --save
  • 配置
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

//1.安装插件
Vue.use(Vuex)

//2.创建对象
const store = new Vuex.Store({
  state: {
    counter: 100
  },
  mutations: {

  },
  actions: {

  },
  getters: {

  },
  modules: {

  }

});
//3.导出store独享
export default store

./main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from "./store";

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})
6.4Vuex状态管理图例

VUE的简单入门_第18张图片

  • Actions:处理异步操作,一般实现外部链接
  • Devtools:浏览器的调试插件
  • Mutations:记录状态变化以及追踪
6.4.1Mutations使用
./index.js
import Vue from 'vue'
import Vuex from 'vuex'

//1.安装插件
Vue.use(Vuex)

//2.创建对象
const store = new Vuex.Store({
  state: {
    counter: 100
  },
  mutations: {
    //方法,默认参数state
    increment(state){
      state.counter++;
    },
    decrement(state){
      state.counter--;
    }
  },
  actions: {

  },
  getters: {

  },
  modules: {

  }

});
//3.导出store独享
export default store

./App.vue
<template>
  <div id="app">
    <h2>{{message}}</h2>
    <h2>{{$store.state.counter}}</h2>
    <button @click="addition">+</button>
    <button @click="subtraction">-</button>
    <hello-vuex></hello-vuex>
  </div>
</template>

<script>
  import HelloVuex from "./components/HelloVuex";
  export default {
    name: 'App',
    components: {HelloVuex},
    data() {
      return{
        message: '我是APP组件',
      }
    },
    methods: {
      addition() {
        this.$store.commit('increment')
      },
      subtraction() {
        this.$store.commit('decrement')
      }
    }
}
</script>
<style>
</style>
6.5Vuex核心概念
6.5.1state
  • state单一状态树Single Source of Truth,也可以翻译为单一数据源
  • Vuex使用了单一状态树来管理应用层级的全部状态
  • 单一状态树能够让我们最直接的方式找到某一个状态的片段,而且在之后的维护和调试过程中,也可以非常方便管理和维护
##获取状态(vue.prototype.$store)
$store.state.状态的变量名
6.5.2getters ----- 数据需要特殊处理
//有时需要从store中获取一些state变异后的状态
./store/index.js
getters: {
  powerCounter(state){
    return state.counter * state.counter
  },
  /*获取年龄大于5的学生*/
  more5stu(state){
    return state.students.filter(s => s.age > 5)
  },
  /*获取年龄大于5的学生个数*/
  more5stuLength(state,getters){
    return getters.more5stu.length
  },
  /*获取年龄大于age(指定)的学生*/
  moreAgestu(state){
    /*return function (age) {
      return state.students.filter(s => s.age > age)
    }*/
    /*同上*/
    return age => {
      return state.students.filter(s => s.age > age)
    }
  }
},
./App.vue
<h2>-----------App内容:getters相关信息-------</h2>
<el>获取当前状态的平方</el>
<h2>{{$store.state.counter * $store.state.counter}}</h2>
<h2>{{$store.getters.powerCounter}}</h2>
<el>获取年龄大于5岁的</el>
<h2>{{more5stu}}</h2>
<h2>{{$store.getters.more5stu}}</h2>
<h2>{{$store.getters.more5stuLength}}</h2>
<h2>{{$store.getters.moreAgestu(3)}}</h2>
6.5.3Mutation
  • Vuex的store状态的更新唯一方式:提交Mutations
  • Mutation主要包含两部分
    • 字符串的事件类型(type)
    • 一个回调函数(handler),该回调函数的第一个参数就是state
mutations: {
  //方法,默认参数state
  //increment   事件类型     (state){state.counter++;}     回调函数     
  increment(state){
    state.counter++;
  },
  decrement(state){
    state.counter--;
  }
}
  • 通过mutation更新
methods: {
  addition() {
    this.$store.commit('increment')
  },
  subtraction() {
    this.$store.commit('decrement')
  }

}
6.5.4mutations更新数据的适合,希望携带一些额外的参数
  • 参数被称为mutation的载荷(Payload)
./App.vue
addCount(count) {
  this.$store.commit('incrementCount',count)
},
addStudent(){
  const stu = {id: 118,name: '达摩院',age: 5}
  this.$store.commit('addStudent',stu)
}

store/index.js
incrementCount(state,count){
  state.counter += count
},
addStudent(state,stu){
  state.students.push(stu)
}
6.5.5Mutations提交风格
addCount(count) {
  //普通的提交封装
  this.$store.commit('incrementCount',count)
  //特殊的提交封装
  this.$store.commit({
    type: 'incrementCount',
    //count: count,//同下(增强写法)
    count
  })
},

incrementCount(state,payload){
  state.counter += payload.count
}
6.6Mutations响应规则
6.6.1概述
  • Vuex的store中的state是响应式的,当state的状态发生改变时,Vue组件会自动更新
  • 必须遵守的一些Vuex对应的规则
  • 提交在store中初始化好所需的属性
  • 当给state中的对象添加新属性时,使用下面的方式:
    - 方式1:使用Vue.set(obj,‘newProp’,123)
    - 方式2:用新对象给旧对象赋值
    VUE的简单入门_第19张图片
updatedInfo(state){
  state.info.name = '华为科技'
  //添加属性
  //state.info['address'] = '深圳'//非响应式的
  Vue.set(state.info,'address','深圳')//响应式的
  //删除
  //delete state.info.age //非响应式的
  Vue.delete(state.info,'age')//响应式的
}

updateInfo(){
  this.$store.commit('updatedInfo')
}
6.6.2Mutations常量类型(官方推荐使用)
//新建store/mutations-types.js
export const INCREMENT = 'increment'

./store/index.js
import {INCREMENT} from "./mutations-types";

[INCREMENT](state){
  state.counter++;
}

./App.vue
addition() {
  this.$store.commit(INCREMENT)
}

6.7action
6.7.1概述
  • Vuex要求我们Mutation中的方法必须是同步方法
  • 主要的原因是当我们使用devtools时,可以devtools可以帮助我们捕捉mutation的快照
  • 但是如果是异步操作,那么devtools将不能很好的追踪这个操作什么时候被完成

VUE的简单入门_第20张图片

6.7.2如果确实需要异步操作,解决方案
  • 如果确实需要进行异步操作,可以是使用Action来代替Mutations进行异步操作(Actions类似于Mutations)
./store/index.js
mutations: {
    updatedInfo(state){
  state.info.name = '华为科技'
  }
}

actions: {
  //context:上下文
  updatedInfo(context,payload){
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        context.commit('updatedInfo')
        console.log(payload);

        resolve('success')
      },1000)
    })
  }
}

./App.vue
updateInfo(){
  /*this.$store.commit('updatedInfo')*/
  /*this.$store.dispatch('updatedInfo',{
    message: '我是携带的信息',
    success: () => {
      console.log('完成修改')
    }
  });*/
  this.$store.dispatch('updatedInfo','我是携带的信息').then(
    (res) => {
      console.log('执行成功');
      console.log(res)
    }
  )
}
6.8module
6.8.1概述
  • Module是模块的意思,为什么Vue中我们要使用模块呢?
  • Vue使用单一状态树,那么也意味着很多状态都会给Vuex来管理
  • 当应用变得非常复杂时,store对象就有可能变得相当臃肿
  • 为了解决这个问题,Vuex允许我们讲store分割成模块(Module),而每个模块拥有自己的state、mutations、actions、getters等
const moduleA = {
  state: {
    name: '四川大学'
  },
  mutations: {
    updateName(state,payload){
      state.name = payload
    }
  },
  actions: {
    updatedName(context){
      setTimeout(() => {
        context.commit('updateName','研究生招生办')
      },1000)
    }
  },
  getters: {
    fullName(state){
      return state.name+'锦江学院'
    },
    fullName2(state,getters){
      return getters.fullName+'教务处'
    },
    fullName3(state,getters,rootState){
      return getters.fullName2+rootState.counter
    }
  },
  //不推荐使用
  modules: {}
}



modules: {
  a: moduleA

}


<h2>------------------App内容:Modules中的内容---------------------</h2>
<h2>{{$store.state.a.name}}</h2>
<button @click="updateName('电子科技大学')">修改学校信息</button>
<h2>{{$store.getters.fullName}}</h2>
<h2>{{$store.getters.fullName2}}</h2>
<h2>{{$store.getters.fullName3}}</h2>
<button @click="updatedName">异步修改信息</button>

updateName(edu){
  this.$store.commit('updateName',edu)
},
updatedName(){
  this.$store.dispatch('updatedName')
}
6.8.2局部状态暴露
//局部状态通过context.state暴露出来,根节点状态则为context.rootState
	const moduleA = {
		actions: {
			//ES6中新特性,context的上下文对象,直接拆解需要的变量,对象的解构
			incrementInfoaddOnRootSum({state,commit,rootState}){
				if((state.count + rootState.count) % 2 ==1){
					commit('increment')
				}
			}
		}
	}
6.8.3补充知识点
  • 项目结构:Vuex帮助我们管理过多的内容时,好的项目结构可以让我们的代码更加清晰
    VUE的简单入门_第21张图片
    VUE的简单入门_第22张图片

8.网络封装

8.1选择什么网络模板
  • 方式1:传统Ajax是基于XMLHttpRequest(XHR)
    • 配置和调用方式等非常混乱
    • 编码起来看起非常不人性化
    • 真实开发过程中很少直接使用,而是使用jQuery-Ajax
  • 方式2:jQuery-Ajax
    • 相对传统的Ajax非常好用
    • Vue的整个开发中都是不需要jQuery
    • 实际开发中没必要为了用网络请求就应用这个重量级的框架(Vue开发)
  • 方式3:Vue-resource
    • Vue-resource体积相对于jQuery小很多
    • Vue-resource是官方推出的
    • 在Vue2.0推出后,不再支持和维护vue-resource
  • 方式4:axios
    • axios有非常多的优点,并且用起来也非常方便
8.2axios功能特点

-在浏览器中发送XMLHttpRequests请求
-在nodejs中发送http请求
-支持Promise API
-拦截请求和响应
-转换请求和响应数据

8.3支持多种请求方式
axios(config)
axios.request(config)
axios.get(url[,config])
axios.delete(url[,config])
axios.head(url[,config])
axios.post(url[,data[,config]])
axios.put(url,[,data[,config]])
axios.patch(url[,data[,config]])
8.4安装axios
##安装
npm install axios --save
8.5axios的基本使用
	axios({
		url: 'http://123.207.32.32:8000/home/multidata',
		//这里可以使用method来指定传输方式
		method: 'get'
		}).then(res => {
			console.log(res)
		})
	axios({
		url: 'http://123.207.32.32:8000/home/date',
		//专门针对get请求的参数拼接
		params: {
			type: 'pop',
			page: 1
		}
	}).then(res => {
		console.log(res);
	})
8.6axios发送并发请求
  • 使用axios.all,可以放入多个请求的数组
  • axios.all([])返回的结果是一个数组,使用axios.spread可将数组(res1,res2)展开为res1,res2
	axios.all([
		axios({
			url: 'http://123.207.32.32:8000/home/multidata'
		}),
		axios({
			url: 'http://123.207.32.32:8000/home/date',
			params: {
				type: 'sell',
				page: 4
			}
		})
	])/*.then(results => {
		console.log(results[0]);
		console.log(results[1]);
	})*///同下
	.then(axios.spread((res1,res2) => {
		console.log(res1);
		console.log(res2);
	}))
8.7全局配置
  • BaseURL是固定的
  • 事实上,在开发中可能很多参数都是固定的
  • 我们可以进行一些抽取也可以利用axios全局配置
	//2.axios发送并发请求
	axios.defaults.baseURL = 'http://123.207.32.32:8000',
	//设置超时时间(连接)ms
	axios.defaults.timeout = 5000
	axios.all([
		axios({
			url: '/home/multidata'
		}),
		axios({
			url: '/home/date',
			params: {
				type: 'sell',
				page: 4
			}
		})
	])/*.then(results => {
		console.log(results[0]);
		console.log(results[1]);
	})*///同下
	.then(axios.spread((res1,res2) => {
		console.log(res1);
		console.log(res2);
	}))
8.8axios的实例模块封装
8.8.1为什么需要创建实例
  • 当我们从axios模块中导入对象时,使用的实例是默认的实例
  • 当给该实例设置一些默认配置时,这些配置就被固定下来了
  • 但是后续开发中,某些配置可能会不太一样
  • 比如某些请求需要使用特定的baseURL或者timeout或者content-Type
  • 我们就可以创建新的实例,并且传入属于该实例的配置信息
//4.创建对应axios的实例
const instance1 = axios.create({
  baseURL: 'http://123.207.32.32:8000',
  timeout: 5000
})
instance1({
  url: '/home/multidata'
}).then(res => {
  console.log(res)
})
instance1({
  url: '/home/data',
  params: {
    type: 'pop',
    page: 1
  }
}).then(res => {
  console.log(res);
})

const instance2 = axios.create({
  baseURL: '',
  timeout: 1000
})
8.8.2axios封装方式很多,如下
  • 公共部分
./network/request.js
import axios from 'axios'

./main.js
import axios from 'axios'
import {request} from "./network/request";
  • 方式1
export function request(config,success,failure) {
  //创建axios实例
  const instance = axios.create({
    baseURL: 'http://123.207.32.32:8000',
    timeout: 5000
  })

  //发送真正的网络请求
  instance(config)
    .then(res => {
      success(res)
    })
    .catch(err => {
      failure(err)
    })

}

request({
  url: '/home/multidata'
},res => {
  console.log(res);
},err => {
  console.log(err);
})
  • 方式2
export function request(config) {
  //创建axios实例
  const instance = axios.create({
    baseURL: 'http://123.207.32.32:8000',
    timeout: 5000
  })

  //发送真正的网络请求
  instance(config.baseConfig)
    .then(res => {
      config.success(res)
  })
    .catch(err => {
      config.failure(err)
    })

}


request({
  baseConfig:{

  },
  success: function(res){

  },
  failure: function(err){

  }
})
  • 方式3
export function request(config) {
  return new Promise((resolve, reject) => {
    //创建axios实例
    const instance = axios.create({
      baseURL: 'http://123.207.32.32:8000',
      timeout: 5000
    })

    //发送真正的网络请求
    instance(config)
      .then(res => {
        resolve(res)
      })
      .catch(err => {
        reject(err)
      })
  })
}

request({
  url: '/home/multidata'
}).then(res => {
  console.log(res);
}).catch(err => {
  console.log(err);
})

-方式4(推荐使用)

export function request(config) {
    //创建axios实例
    const instance = axios.create({
      baseURL: 'http://123.207.32.32:8000',
      timeout: 5000
    })
    //发送真正的网络请求
    return instance(config)
}


request({
  url: '/home/multidata'
}).then(res => {
  console.log(res);
}).catch(err => {
  console.log(err);
})
8.9axios的拦截器的使用
  • axios提供了拦截器,用于我们在发送每次请求或者得到相应后,进行对应的处理
export function request(config) {

    //创建axios实例
    const instance = axios.create({
      baseURL: 'http://123.207.32.32:8000',
      timeout: 5000
    })
    //axios的拦截器
    //请求拦截
    instance.interceptors.request.use(config => {
      console.log(config);
      //比如,config的某些信息不符合服务器的要求,对信息进行转化
      //比如,每次发送网络请求时,都希望在界面中显示一个请求图标
      //比如,某些网络请求(比如登录),必须携带一些特殊信息

      //拦截之后,将进行下一步,将config返回
      return config;
    },err => {
      console.log(err);
    })
    //响应拦截
    instance.interceptors.response.use(res => {
      console.log(res);
      //返回数据
      return res.data;
    },err => {
      console.log(err);
    });
    //发送真正的网络请求
    return instance(config)

}

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