Vue从小白到入门(保姆级教学)

news2024/11/26 19:36:15

文章目录

    • 🍋Vue是什么?
      • 🍋MVVM思想
    • 🍋vue2快速入门
      • 🍋注意事项
    • 🍋数据单向渲染
    • 🍋数据双向渲染
      • 🍋作业布置
    • 🍋事件绑定
      • 🍋事件处理机制
      • 🍋注意事项和细节
      • 🍋作业布置
    • 🍋修饰符
      • 🍋扩展案例
    • 🍋条件渲染/控制
      • 🍋v-if介绍
      • 🍋v-show介绍
      • 🍋机制剖析
      • 🍋作业布置
    • 🍋列表渲染
      • 🍋作业布置
    • 🍋组件化编程
      • 🍋非组件化编程
      • 🍋全局组件
      • 🍋局部组件
      • 🍋全局组件VS局部组件
      • 🍋注意事项
    • 🍋生命周期和监听函数
      • 🍋vue生命周期图示
      • 🍋应用实例
      • 🍋作业布置
    • 🍋Vue2 Cli 脚手架
      • 🍋环境配置, 搭建项目
      • 🍋IDEA配置项目
      • 🍋vue项目结构分析
      • 🍋项目执行流程
      • 🍋路由器作业
      • 🍋路由器应用实例
    • 🍋ElementUI
      • 🍋基本使用
      • 🍋课后作业
    • 🍋Axios
      • 🍋Axios库文件
      • 🍋 Axios应用实例
      • 🍋注意事项和细节

🍋Vue是什么?

  1. Vue(读音 /vju:/, 类似于 view) 是一个前端框架, 易于构建用户界面
  2. Vue的核心库只关注试图层, 不仅易于上手, 还便于与第三方库或项目整合
  3. 支持和其它类库结合使用
  4. 开发复杂的单页应用非常方便
  5. Vue 是 Vue.js的简称

🍋MVVM思想

图解在这里插入图片描述

  1. M: 即 Model, 模型, 包括数据和一些基本操作.
  2. V: 即 View, 视图, 页面渲染结果.
  3. VM: 即 View-Model, 模型与视图间的双向操作(无需开发人员干涉).
  4. 在 MVVM 之前, 开发人员从后端获取需要的数据模型, 然后要通过DOM操作Model, , 把数据渲染到View中. 而后当用户操作视图, 我们还需要通过DOM操作获取View中的数据, 然后同步到Model中.
  5. 而MVVM中的 VM 要做的事情就是把DOM操作完全封装起来, 开发人员不用再关心Model 和 View之间是如何互相影响的.
  6. 只要我们 Model 发生了变化, View上自然就会表现出来.
  7. 当用户修改了 View, Model 中的数据也会跟着改变.

结果: 把开发人员从繁琐的DOM操作中解放出来, 把关注点放在如何操作Model上, 大大提高我们的开发效率.

🍋vue2快速入门

  1. 需求: 初步体会 vue.js 的数据绑定功能
  2. 体会 vue.js 开发框架的主体结构

为了让IDEA识别Vue代码, 需要安装插件 Vue.js
在这里插入图片描述新建一个空白文件夹, 拖拽到桌面Idea图标处, 打开
在这里插入图片描述 将vue.js复制到项目中, vue.js下载官网
这里下载的是开发版本
在这里插入图片描述新建页面 quick_start.html -> 数据绑定机制验证

<body>
<!--
    1.div元素不是必须的, 也可以是其它元素, 比如span, 但是约定都是将vue实例挂载到div下
    因为div更加适合做布局
    2.id 不是必须为app, 是程序员指定的, 一般我们就使用app
-->
<div id="app">
    <!--
        1.{{message}}: 插值表达式
        2.message 就是从model的data数据池来设置
        3.当我们的代码执行时, 会到我们的data数据池中去匹配我们的数据.
        4.如果匹配上, 就进行替换; 如果没有匹配上, 就会输出空
    -->
    <h1>欢迎{{message}}--{{name}}</h1>
</div>
<!--引入vue.js-->
<script src="vue.js"></script>
<script>
    //创建Vue对象
    /**
     * 1.创建Vue对象实例
     * 2.我们在控制台输出vm对象, 看看该对象的结构! 数据在哪里 listeners在哪里
     */
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "hello-Vue!",
            name: "赵志伟"
        }
    });

    console.log("vm=>", vm);
    console.log(vm._data.message);
    console.log(vm._data.name);
    console.log(vm.message);
    console.log(vm.name);
</script>
</body>

🍋注意事项

  1. 注意代码顺序, 要求div在前, script在后, 否则无法绑定数据
  2. 从案例可以体会声明式渲染: Vue.js 采用简洁的模板语法来声明式地将数据渲染进DOM的系统, 做到数据和显示分离
  3. Vue没有繁琐的DOM操作, 如果使用jQuery, 我们需要先找到div节点, 获取到DOM对象, 然后进行节点操作, 显然没有Vue更加简洁

🍋数据单向渲染

需求: 演示v-bind 的使用, 可以绑定元素的属性

  1. 插值表达式是在标签体的
  2. 如果给标签属性绑定值, 则使用 v-bind 指令
<body>
<div id="app">
    <h1>{{message}}</h1>
    <!--
        1.使用插值表达式 引用data数据池 数据是在标签体内
        2.如果是在标签/元素的属性上去引用data数据池数据时, 不能使用插值表达式
        3.需要使用v-bind, 因为b-bind是由vue解析的, 默认爆红, 但是不影响解析
        4.如果不希望看到爆红, 直接alt+enter引入 xmlns:v-bind
        5.v-bind: 可以简写成一个冒号
    -->
    <!--<img src="{{img_src}}">-->
    <img v-bind:src="img_src" v-bind:width="img_width">
    <img :src="img_src" :width="img_width">
</div>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "Hello-温暖女孩!",
            img_src: "1.jpg",
            img_width: "200px"
        }
    });
    console.log("vm=>", vm);
</script>

🍋数据双向渲染

需求: 在输入框中输入信息, 会更新到相应绑定的位置
在这里插入图片描述

在这里插入图片描述

<div id="app">
    <h1>{{message}}</h1>
    <!--解读
    1.v-bind是数据单项渲染: data数据池绑定的数据变化, 会影响view
    2.v-model="hobby.val" 是数据的双向渲染
        (1)data数据池绑定的数据变化, 会影响View -> 底层机制是 Data Bindings
        (2)view 关联的元素变化, 会影响到data数据池的数据 -> 底层机制是 Dom Listeners
    -->
    <input type="text" v-model="hobby.val"/><br/><br/>
    <input type="text" :value="hobby.val"/><br/><br/>
    <p>你输入的爱好是: {{hobby.val}}</p>
</div>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "你好, 输入你的爱好!",
            hobby: {
                val: "购物"
            }
        }
    });
    console.log("vm=>", vm);
</script>

🍋作业布置

使用Vue的数据双向绑定, 完成

  1. 当用户在输入框输入1,jpg, 2.jpg, 3.jpg时可以切换显示对应的图片
  2. 使用Vue的数据双向绑定, 完成
<body>
<div id="app">
    <h1>{{message}}</h1>
    <!--
    1.这里我们使用了数据的双向渲染-data{}数据池的img_src
    -->
    <input type="text" v-model="img_src"/><br/><br/>
    <img v-bind:src="img_src" v-bind:width="img_width"/><br/><br/>
    <img src="1.jpg" v-bind:width="img_width"/>
    <img src="2.jpg" v-bind:width="img_width"/>
    <img src="3.jpg" v-bind:width="img_width"/>
</div>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "请输入图片编号 1.jpg, 2.jpg, 3.jpg!",
            img_src: "1.jpg",
            img_width: "400px"
        }
    });
    console.log("vm=>", vm);
</script>
</body>

🍋事件绑定

基本说明

  1. 使用 v-on 进行事件处理, 比如: v-on: click 表示处理鼠标点击事件
  2. 时间调用的方法定义在 vue 对象声明的methods节点中
  3. v-on: 事件名, 可以绑定指定事件
  4. 官方网站: https://v2.cn.vuejs.org/v2/guide/events.html

需求: 演示Vue事件绑定操作

<body>
<div id="app">
    <h1>{{message}}</h1>
    <!--
    1.v-on:click 表示我们要给button元素, 绑定一个click事件
    2.sayHi() 表示绑定的方法, 在我们的方法池 methods{} 中定义
    3.这里需要js的基础, 底层仍然是dom编程
    4.如果方法不需要传递参数, 可以省略() [主流浏览器都是支持这个写法的]
    5.v-on:click 可以简写成 @click, [需要浏览器支持, 主流浏览器都支持]
    -->
    <button v-on:click="sayHi()">点击输出</button>
    <button v-on:click="sayOk()">点击输出</button>
    <button v-on:click="sayHi">点击输出</button>
    <button @click="sayOk">点击输出</button>
</div>
<script src="vue.js"></script>
<script>
    //1.创建一个Vue实例, 并挂载到id=app的div上, el 就是element的简写
    //2.这里创建的Vue实例, 可以不去接受, 也可以去接受. 接收方便我们调试信息
    let vm = new Vue({
        el: "#app",
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "vue事件处理的案例 ",
        },
        //解读:
        // 1.是一个methods属性, 对应的值是对象{}
        // 2.在{ }中, 可以写很多的方法, 可以理解成是一个方法池
        methods: {
            sayHi() {
                console.log("hi, 银角大王");
            },
            sayOk() {
                console.log("hi, 金角大王");
            },
        },
    });
</script>
</body>

🍋事件处理机制

底层仍然是DOM编程
在这里插入图片描述

🍋注意事项和细节

  1. 如果方法不需要传递参数, 可以省略() [主流浏览器都是支持这个写法的]
  2. v-on:click 可以简写成 @click, [需要浏览器支持, 主流浏览器都支持]
  3. 在挂载的div的某个元素上可以查看可以绑定的事件, 通过控制台

Vue 输入框组件 @input、@keyup.enter、@change、@blur
vm -> $el -> childNodes -> Button节点下查看
在这里插入图片描述

🍋作业布置

需求: 点击按钮, 次数联动变化

  1. 当用户 “点击增加+1” 按钮时, 次数+1
  2. 当用户 “点击增加+2” 按钮时, 次数+2
  3. 使用常规方法和表达式形式完成(两种方式都要掌握)
<body>
<div id="app">
    <h1>{{message}}</h1>
    <button v-on:click="add">点击增加+1</button>
    <!--
    第二种写法
    1.这里 count += 2 的count数据是data数据池的count
    -->
    <button @click="count += 2">点击增加+2</button>
    <p>你的按钮被点击了{{count}}次</p>
</div>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "演示Vue事件绑定操作",
            count: 0,//点击的次数
        },
        methods: {
            add() {
                //修改data数据池中的数据
                //因为data和methods在同一个Vue实例中, 因此可以通过 this.数据名 来获取
                //this在对象中使用, 在这里是vm实例
                this.count += 1;
                // vm.count += 1;
                // vm._data.count += 1;
                // this._data.count += 1;
                // vm.$data.count += 1;
                // this.$data.count += 1;
            },
        },
    });
</script>
</body>

获取/修改 数据池数据的两种方式
在这里插入图片描述

需求: 根据用户的输入, 弹窗显示内容

  1. 用户可以在输入框输入内容
  2. 点击按钮, 可以显示书名
<body>
<div id="app">
    <h1>{{message}}</h1>
    书名: <input type="text" v-model="bookName"/>
    <button v-on:click="listBook">点击显示输入框的内容</button>
</div>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "演示Vue事件绑定操作",
            bookName: "笑傲江湖~",
        },
        //解读:
        // 1.是一个methods属性, 对应的值是对象{}
        // 2.在{ }中, 可以写很多的方法, 可以理解成是一个方法池
        methods: {
            listBook() {
                //this在对象中使用, this 当前对象
                //this要带上, 否则报错 "ReferenceError: bookName is not defined"
                alert("书名=" + bookName);
            },
        },
    });
</script>
</body>

🍋修饰符

基本说明

  1. 修饰符(Modifiers)是以 ( . ) 指明的后缀, 指出某个指令以特殊方式绑定
  2. 官方文档: https://v2.cn.vuejs.org/v2/guide/events.html#事件修饰符

需求: 演示v-on:submit.prevent 的使用, 如果没有输入名字, 控制台输出 “请输入名字”, 否则输出 “提交表单”

  1. 为什么在开发中, 有时需要, 让某个指令以特殊方式提交, 比如表单提交
  2. 我们不希望这个表单进行整体提交, 而是以Ajax的方式进行提交
  3. 因为表单整体提交会导致重载页面, 而Ajax方式可以有选择性地提交数据, 并且可局部刷新
<body>
<div id="app">
    <!--
        1.修饰符用于指出一个指令应该以特殊方式绑定
        2.v-on:submit.prevent的.prevent 修饰符表示阻止表单提交的默认行为
        3.执行 程序员 指定的方法
    -->
    <form action="http://www.baidu.com" v-on:submit.prevent="mySubmit">
        妖怪名: <input type="text" v-model="monster.name"><br/><br/>
        <button type="submit">注册</button>
    </form>
    <p>服务器回送的数据是{{count}}</p>
</div>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {//数据池
            monster: {//monster数据(对象)的属性, 可以动态生成
            },
            count: 0,
        },
        methods: {//方法池
            mySubmit() {
                // 这里不能用this.name获取
                if (this.monster.name) {// "" undefined都是false
                    console.log("提交表单 name=", this.monster.name);
                    //这里, 程序员就可以根据自己的业务发出ajax请求到后端
                    //得到数据后,再进行数据更新-局部刷新
                    this.count = 1;
                } else {
                    console.log("请输入名字");
                }
            },
        },
    });
</script>
</body>

在这里插入图片描述
在这里插入图片描述

🍋扩展案例

  • 案件修饰符

为了在必要的情况下支持旧浏览器, Vue提供了绝大多数常用的按键码的别名.enter .tab .delete .esc .space .up .down .left .right

<h1>修饰符扩展案例</h1>
<!--在同一个页面, 只能点击一次-->
<button v-on:click.once="onMySubmit">点击一次</button><br/><br/>
<!--按键修饰符-->
<input type="text" v-on:keyup.enter="onMySubmit">
<input type="text" v-on:keyup.right="onMySubmit">
<!--去掉两边的空格-->
<input type="text" v-model.trim="count">

🍋条件渲染/控制

Vue提供了v-if 和 v-show 条件指令完成条件渲染/控制
官方文档: https://v2.cn.vuejs.org/v2/guide/conditional.html

🍋v-if介绍

v-if指令用于条件性地渲染一块内容, 这块内容只会在指令的表达式返回true值时被渲染
细节: count是要往data数据池中找的, 如果count为true, 那么这个标题被输出; 如果在data数据池中没有找到这个变量, count返回undefined, 在js中, undefined为false, 则不会被渲染

<h1 v-if="count">hello</h1>

也可以用v-else添加一个"else"块

<h1 v-if="count">hello</h1>
<h1 v-else>no 😊</h1>

应用实例

<body>
<div id="app">
    <!--
    这里还可以看到checkbox的 checked属性值
    在vm实例$el属性 childNodes下找到checkbox节点
    -->
    <input type="checkbox" v-model="ok"/>是否同意条款[v-if实现]
    <h1 v-if="ok">你同意条款</h1>
    <h1 v-else>你不同意条款</h1>
</div>
<script src="vue.js"></script>
<script>
    //为了调试方便, 用vm来接收Vue实例
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            ok: false,
        }
    });
</script>
</body>

🍋v-show介绍

另一个用于根据条件展示元素的选项是v-show指令, 用法大致一样
细节: 去data数据池中获取ok的值, 如果ok值为true, 标签被渲染; 如果ok值为false, 不会被渲染

<h1 v-show="ok">hello</h1>

应用实例

<input type="checkbox" v-model="ok"/>是否同意条款[v-show实现]
<!--这里的ok不要把它理解为字符串, 它是数据池里的一个变量-->
<h1 v-show="ok">你同意条款</h1>
<h1 v-show="!ok">你不同意条款</h1>

🍋机制剖析

v-if会确保在切换过程中, 条件块内的事件监听器和子组件销毁和重建
演示: 方式一
在这里插入图片描述
演示: 方式二 vm -> $el -> childNodes -> h1标签
在这里插入图片描述
v-show不管初始条件是什么, 元素总是被渲染, 并且只是对CSS进行切换
演示: 方式一
在这里插入图片描述
演示: 方式二
在这里插入图片描述
使用建议: 如果要频繁地切换, 建议使用v-show; 如果运行时条件很少改变, 使用v-if较好

🍋作业布置

需求: 当用户输入成绩时, 可以输出对应的级别

  1. 90分以上, 显示优秀
  2. 79分以上, 显示良好
  3. 60分以上, 显示及格
  4. 低于60分, 显示不及格
  5. 如果用户输入的成绩大于100, 就修正成100; 如果用户输入的成绩小于0, 就修正成0

Vue 输入框组件 @input、@keyup.enter、@change、@blur

<body>
<div id="app">
    <h1>{{message}}</h1>
    <!--思路
    1.当用户输入成绩后, 我们判断成绩的范围, 并进行修正
    2.事件处理: input 实时监听事件,只要输入的值变化了就会触发input
    -->
    输入成绩1-100: <input type="text" v-model="score" v-on:input="correct"/>
    <p>你当前的成绩是 {{score}}</p>
    <p v-if="score >= 90">优秀</p>
    <p v-else-if="score >= 70">良好</p>
    <p v-else-if="score >= 60">及格</p>
    <p v-else>不及格</p>
</div>
<script src="vue.js"></script>
<script>
    //为了调试方便, 用vm来接收Vue实例
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //data{} 表示数据池[model的数据池有了数据], 有很多数据, 以k-v形式设置(根据业务需要来设置)
            message: "演示条件判断",
            score: "",//当前的成绩
        },
        methods: {
            correct() {
                //判断成绩并修正
                this.score = (this.score > 100) ? 100 : this.score;

                this.score = (this.score < 0) ? "" : this.score;
            },
        }
    });
</script>
</body>

🍋列表渲染

基本说明

  1. Vue提供了 v-for 列表循环指令
    官网文档: https://v2.cn.vuejs.org/v2/guide/list.html
<body>
<div id="app">
    <ul>
        <h1>简单的列表渲染</h1>
        <li v-for="i in 3">{{i}}</li>
    </ul>
    <ul>
        <h1>简单的列表渲染-带索引</h1>
        <!--索引不一定要用index表示, 只是一般是用index-->
        <li v-for="(j, index) in 3">{{j}} - {{index}}</li>
    </ul>
    <h1>遍历数据列表</h1>
    <table border="1px" width="500px">
        <tr v-for="(monster, index) in monsters">
            <td>{{index}}</td>
            <td>{{monster.id}}</td>
            <td>{{monster.name}}</td>
            <td>{{monster.age}}</td>
        </tr>
    </table>
</div>
<script src="vue.js"></script>
<script>
    //为了调试方便, 用vm来接收Vue实例
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //数据池
            monsters: [
                {id:1, name:"牛魔王", age:800},
                {id:2, name:"齐天大圣", age:900},
                {id:3, name:"红孩儿", age:200},
            ]
        },
    });
</script>
</body>

🍋作业布置

需求: 显示成绩及格的学生列表

  1. 将学生对象, 存放在数组中
  2. 遍历显示所有学生, 只显示成绩及格的学员
<body>
<div id="app">
    <h1>{{message}}</h1>
    <table border="1px" width="300px">
        <tr>
            <td>index</td>
            <td>id</td>
            <td>name</td>
            <td>age</td>
            <td>score</td>
        </tr>
        <tr v-for="(student, index) in students">
            <template v-if="student.score >= 60">
                <td>{{index}}</td>
                <td>{{student.id}}</td>
                <td>{{student.name}}</td>
                <td>{{student.age}}</td>
                <td>{{student.score}}</td>
            </template>
        </tr>
    </table>
</div>
<script src="vue.js"></script>
<script>
    //为了调试方便, 用vm来接收Vue实例
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //数据池
            message: "学生成绩列表-及格的学生",
            students: [
                {id: 1, name: "jack", age: 20, score: 90},
                {id: 2, name: "john", age: 19, score: 55},
                {id: 3, name: "tom", age: 21, score: 42},
                {id: 4, name: "mary", age: 20, score: 60}
            ]
        },
    });
</script>
</body>

🍋组件化编程

基本说明

  1. 在大型应用开发的时候, 页面可以划分为很多部分, 往往不同的页面, 会有相同的部分. 例如可能会有相同的头部导航.
  2. 但是如果每个页面都独自开发, 这无疑增加了我们开发的成本. 所以我们会把页面的不同部分拆分成独立的组件, 然后在不同页面就可以共享这些组件, 避免重复开发
  • 组件(Component)是 Vue.js最强大的功能之一[可以提高复用性(1.界面 2.业务逻辑)]
  • 组件也是一个Vue实例, 也包括: data, methods, 生命周期函数等
  • 组件渲染需要html模板, 所以增加了template属性, 值就是html模板
  • 对于全局组件, 任何vue实例都可以直接在html中通过组件名称来使用组件
  • data是一个函数, 不再是一个对象, 这样每次引用组件都是独立的对象/数据

🍋非组件化编程

<body>
<div id="app">
  <!--非组件化方式 - 普通方式-->
  <button v-on:click="click1()">点击次数= {{count}}次 [非组件化方式]</button><br/><br/>
  <!--有多个按钮, 都要进行点击统计-->
  <!--
  1.其实三个按钮的界面一样, 但是目前我们都重新写了一次, 复用性低
  2.点击各个按钮的业务都是对 次数+1, 因此业务处理类似, 但是也都重新写了一次, 复用性低
  3.解决: 组件化编程
  -->
  <button v-on:click="click2()">点击次数= {{count2}}次 [非组件化方式]</button><br/><br/>
  <button v-on:click="click3()">点击次数= {{count3}}次 [非组件化方式]</button><br/><br/>
</div>
<script src="vue.js"></script>
<script>
  //为了调试方便, 用vm来接收Vue实例
  let vm = new Vue({
    el: "#app",//创建的vue实例挂载到id=app的div
    data: { //数据池
      count: 0,
      count2: 0,
      count3: 0,
    },
    methods: {//methods属性, 可以定义相应的方法
      click1() {
        this.count++;
      },
      click2() {
        this.count2++;
      },
      click3() {
        this.count3++;
      },
    }
  });
</script>
</body>

🍋全局组件

<body>
<div id="app">
    <h1>{{message}}</h1>
    <!--使用全局组件-->
    <counter></counter><br/><br/>
    <counter></counter>
</div>
<script src="vue.js"></script>
<script>
    //1.定义一个全局组件, 名称为counter
    //2.{} 表示我们组件相关的内容
    //3.template用于指定该组件的界面, 因为会引用到数据池里的数据, 所以需要使用模板字符串
    //4.这里要特别强调: 要把组件视为一个Vue实例, 也有自己的数据池和methods
    //5.特别说明: 对于组件, 我们的数据池的数据是使用函数/方法返回[目的是为了保证每个组件的数据是独立的], 不能使用原来的方式
    //6.这时我们就达到了, 界面通过template实现共享, 业务处理也复用
    Vue.component("counter", {
        template: `<button v-on:click="click()">点击次数= {{count}}次 [全局组件化]</button>`,
        /*data: {//错误方式 The "data" option should be a function that returns a per-instance value in component definitions.
            count: 10
        },*/
        data() {//这里需要注意, 和原来的方式不一样!!!
            return {
                count: 10,
            }
        },
        methods: {
            click() {
                this.count++;
            },
        }
    })
    //为了调试方便, 用vm来接收Vue实例
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        data: { //数据池
            message: "组件化编程-全局组件",
        }
    });
</script>
</body>

🍋局部组件

<body>
<div id="app">
    <h1>{{message}}</h1>
    <!--使用局部组件, 该组件是从挂载到app的vue中来的-->
    <my_counter></my_counter><br/><br/>
    <my_counter></my_counter><br/><br/>
    <my_counter></my_counter><br/><br/>
</div>
<script src="vue.js"></script>
<script>
    //定义一个组件, 组件的名称为 buttonCounter
    //扩展: 1.将来可以把常用的组件, 定义在某个commons.js中
    //     2.如果某个页面需要使用, 直接import
    const buttonCounter = {
        template: `<button v-on:click="click()">点击次数= {{count}}次 [局部组件化]</button>`,
        data() {//这里需要注意, 和原来的方式不一样!!!
            return {
                count: 10,
            }
        },
        methods: {
            click() {
                this.count++;
            },
        }
    };

    //为了调试方便, 用vm来接收Vue实例
    let vm = new Vue({
        el: "#app",//创建的vue实例挂载到id=app的div
        components: {//引入某个组件, 此时my_counter就是一个组件, 它是一个局部组件, 它的适用范围就在当前的Vue实例中
            "my_counter": buttonCounter,
        },
        data: { //数据池
            message: "组件化编程-局部组件",
        }
    });
</script>
</body>

🍋全局组件VS局部组件

全局组件是属于所有Vue实例, 因此可以在所有Vue实例中使用

<body>
<div id="app">
    <h1>组件化编程-全局组件</h1>
    <!--使用全局组件-->
    <counter></counter><br/><br/>
    <counter></counter>
</div>
<div id="app2">
    <h1>组件化编程-全局组件-app2</h1>
    <!--使用全局组件-->
    <counter></counter><br/><br/>
    <counter></counter>
</div>
<script src="vue.js"></script>
<script>
    Vue.component("counter", {
        template: `<button v-on:click="click()">点击次数= {{count}}次 [全局组件化]</button>`,
        data() {
            return {
                count: 10,
            }
        },
        methods: {
            click() {
                this.count++;
            },
        }
    })
    let vm = new Vue({
        el: "#app",
    });
    let vm2 = new Vue({
        el: "#app2",
    });
</script>
</body>

局部组件, 作用范围只在引入这个组件的Vue实例中

<div id="app">
    <h1>组件化编程-局部组件</h1>
    <my_counter></my_counter><br/><br/>
    <my_counter></my_counter>
</div>
<div id="app2">
    <h1>组件化编程-局部组件-app2</h1>
    <zzw_counter></zzw_counter><br/><br/>
    <zzw_counter></zzw_counter>
</div>
<script src="vue.js"></script>
<script>
    const buttonCounter = {
        template: `<button v-on:click="click()">点击次数= {{count}}[局部组件化]</button>`,
        data() {
            return {
                count: 10,
            }
        },
        methods: {
            click() {
                this.count++;
            },
        }
    };

    let vm = new Vue({
        el: "#app",
        components: {
            "my_counter": buttonCounter,
        },
    });
    let vm2 = new Vue({
        el: "#app2",
        components: {
            "zzw_counter": buttonCounter,
        },
    });
</script>
</body>

🍋注意事项

  1. 组件定义需要放置在new Vue()之前, 否则组件注册会失败
  2. 组件也是一个Vue实例, 也包括: data, methods, 生命周期函数等
  3. 组件渲染需要html模板, 所以增加了template属性, 值就是html模板
  4. data是一个函数, 不再是一个对象, 这样每次引用组件都是独立的对象/数据

🍋生命周期和监听函数

基本说明

  1. Vue实例有一个完整的生命周期, 也就是说从开始创建, 初始化数据, 编译模板, 挂载DOM, 渲染-更新-渲染, 卸载等一系列过程, 我们成为Vue实例的生命周期
  2. 钩子函数(监听函数): Vue实例在完整的生命周期过程中(比如设置数据监听, 编译模板, 将实例挂载到DOM, 在数据变化时更新DOM等), 也会运行叫做生命周期钩子(hook)的函数
  3. 钩子函数的作用: 就是在某个阶段, 给程序员一个做某些处理的机会
  4. Vue实例生命周期非常重要, Vue编程模型都是建立在此基础上
  5. 官网文档: https://v2.cn.vuejs.org/v2/guide/instance.html#生命周期图示

🍋vue生命周期图示

  1. new Vue()
    new 了一个Vue的实例对象, 此时就会进入组件的创建过程
  2. Init Events & Lifecycle
    初始化组件的事件和生命周期函数 (Vue底层来做的, 无法干预)
  3. beforeCreate
    组件创建之后遇到的第一个生命周期函数, 这个阶段data和methods以及dom结构都未被初始化, 也就是获取不到data的值, 不能调用methods中的函数
  4. Init injections & reactivity
    这个阶段中, 正在初始化data和methods中的方法
  5. created
    这个阶段组件的data和methods中的方法已经初始化结束, 可以访问. 但dom结构未初始化, 页面未渲染
    特别说明: 在这个阶段, 经常会发出Ajax请求
  6. 编译模板结构(在内存中, 由Vue底层实现的, 不用参与)
  7. beforeMount
    当模板在内存中编译完成, 此时内存中的模板结构还未渲染至页面, 还是看不到真实的数据
  8. Create vm.$el and replace “el” with it
    这一步, 再把内存中渲染好的模板结构替换至真实的dom结构, 也就是页面上
  9. mounted
    此时, 页面已渲染好, 用户看到的是真实的页面数据, 生命周期创建阶段完毕, 进入到了运行中的阶段
  10. 生命周期运行中
  • 10.1 beforeUpdate
    当执行此函数, 数据池的数据是新的, 但是页面上的数据是旧的
  • 10.2 Virtual DOM re-render and patch
    根据最新的data数据, 重新渲染内存中的模板结构(修补一下内存模板, 类似于打补丁,把修补好的内存模板替换到页面上), 并把渲染好的模板结构, 替换至页面上
  • 10.3 updated
    页面已经完成了更新. 此时, data数据池和页面的数据都是新的
  1. beforeDestroy
    当执行此函数时, 组件即将被销毁, 但是还没有真正开始销毁, 此时组件的data, methods数据或方法 还可以被调用
  2. Teardown[拆卸]…
    注销组件和事件监听
  3. destroyed
    组件已经完成了销毁
    在这里插入图片描述

🍋应用实例

需求: 展示vue实例生命周期和钩子函数/监听函数/生命周期函数 执行时机

  1. 重点展示几个重要的钩子函数(beforeCreate, created, beforeMount, mounted, beforeUpdate, updated)
  2. 在这几个钩子函数中, 数据模型是否加载/使用?
    自定义方法是否加载/使用?
    html模板(页面DOM)是否加载/使用?
    html模板是否完成渲染(插值表达式是否更新)?

学习小技巧/起到大作用: 自己对某个知识有疑问, 可以设计一些小案例, 来验证

Vue实例生命周期非常重要, Vue编程模型都是建立在此基础上

<body>
<!--这里可以视为用户看到的页面, 对应前面讲解的页面dom-->
<div id="app">
    <span id="num">{{num}}</span>
    <button @click="num++">点赞!</button>
    <h2>{{name}}, 有{{num}}次点赞</h2>
</div>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            name: "Kristina",
            num: 0,
        },
        methods: {
            show() {
                return this.name;
            },
            add() {
                this.num++;
            },
        },
        beforeCreate() {//生命周期函数-创建Vue实例前
            console.log("============beforeCreate============");
            console.log("数据模型/数据池的数据 是否加载/是否能使用? [不能使用]", this.name, " ", this.num);//undefined undefined
            // console.log("自定义的方法 是否加载/是否能使用? [不能使用]", this.show());//Error in beforeCreate hook: "TypeError: this.show is not a function"
            console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
            console.log("用户的页面dom 是否被渲染? [未被渲染]", document.getElementById("num").innerText);//{{num}}
        },
        created() {//生命周期函数-创建Vue实例后
            console.log("============created============");
            console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
            console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
            console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
            //内存模型还未编译, 外面的页面dom肯定不会被渲染
            console.log("用户的页面dom 是否被渲染? [未被渲染]", document.getElementById("num").innerText);//{{num}}
            //可以发出Ajax请求
            //接收返回的数据
            //再次更新data数据池的数据
            //编译内存模板结构
            //挂载
            //...替换
        },
        beforeMount() {//生命周期函数-挂载前
            console.log("============beforeMount============");
            console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
            console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
            console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
            //还没有把内存编译好的模板替换到用户页面的dom结构上, 仍然看不到渲染后的结果
            console.log("用户的页面dom 是否被渲染? [未被渲染]", document.getElementById("num").innerText);//{{num}}
        },
        mounted() {//生命周期函数-挂载后
            console.log("============mounted============");
            console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
            console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
            console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
            //把内存中的模板替换到el上, 即挂载点上
            console.log("用户的页面dom 是否被渲染? [已经渲染]", document.getElementById("num").innerText);//0
        },
        beforeUpdate() {//生命周期函数-页面数据更新前
            console.log("============beforeUpdate============");
            console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
            console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
            console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
            console.log("用户的页面dom 是否被更新? [未被更新]", document.getElementById("num").innerText);//0
            //验证前如果数据有错误, 需要修正数据
            //举个例子
            // if (this.num < 10) {
            //     this.num = 10;
            // }
        },
        updated() {//生命周期函数-页面数据更新后
            console.log("============updated============");
            console.log("数据模型/数据池的数据 是否加载/是否能使用? [可以使用]", this.name, " ", this.num);//Kristina 0
            console.log("自定义的方法 是否加载/是否能使用? [可以使用]", this.show());//Kristina
            console.log("用户的页面dom 是否被加载? [已经加载]", document.getElementById("num"));
            console.log("用户的页面dom 是否被更新? [已经更新]", document.getElementById("num").innerText);//1
        },
    })
</script>
</body>

🍋作业布置

  1. 请简述Vue实例的生命周期流程

回答一: 创建前-创建后-挂载前-挂载后-销毁前-销毁后
回答二: 创建前, 初始化事件和生命周期; 创建后, 加载数据池数据和方法池自定义方法; 挂载前, 编译内存模板, 形成内存模板结构; 挂载后, 页面已被渲染, 可以看到最新数据; 更新前, 已监听到数据池数据变化, 数据池变化有可能是前端传来的数据[双向绑定], 或者是点击某个按钮, 导致数据池数据变化, 也有可能是后端传来的数据导致数据池数据变化; 更新后, 会重新渲染内存模板结构(修补一下内存模板, 类似于打补丁,把修补好的内存模板替换到页面上), 并把渲染好的模板结构, 替换至页面上(); 销毁前, 数据和方法还能访问; 销毁后, 数据和方法已不能再访问.
回答三: 在new一个Vue实例后, 会执行Init Events & lifecycle, Vue底层来做的, 无法干预. 即初始化事件和生命周期. 这时, 在beforeCreate()函数中, 数据池中的数据和方法池中自定义的方法还未被加载, 但div模板已加载, 前端页面还拿不到数据池中的数据. 接下来, 会进行Init injections & reactivity, 即会注入数据, 会加载/初始化数据池和方法池中自定义的方法, 在create()函数中, 会拿到数据池中的数据和方法池中自定义的方法, 但这时前端界面仍然拿不到数据.接下来, 会判断有无$el, 有无template, 会在内存中形成一个模板, 即内存模板结构, 此时还未把内存模板挂载到div上, 所有前端页面仍然拿不到数据. 在beforeMount()函数执行之前, 即在挂载之前, 内存模板已经编译好, 之后会进行挂载Compile template into render function *, 这时内存模板已经挂载到页面dom上, 在挂载之后执行的mounted()函数中, 已经可以看到最新渲染过后的页面. 当页面拿到数据后, 程序会监听数据池中的数据变化 (数据池变化有可能是前端传来的数据[双向绑定],或者是点击某个按钮导致数据池数据变化, 也有可能是后端传来的数据导致数据池数据变化), 当监听到数据变化时, 会触发生命周期函数beforeUpdate, 这时函数内已经可以拿到数据池新的数据, 但是这数据还未更新到页面DOM上, 页面上还是显示的上一次的数据. 之后会进行Virtual DOM re-render and patch, 会进行重新渲染和打补丁( 会重新渲染内存模板结构,[修补一下内存模板, 类似于打补丁, 把修补好的内存模板替换到页面上] 并把渲染好的模板结构, 替换至页面上. ). 这时, 之后执行的updated()函数中, 已经可以看到页面上最新的数据. 最后, 在Vue实例即将销毁时, 即when vm.$destroy() is called, 在销毁方法即将被调用时, 会执行一个beforeDestroy()函数, 这时, 数据池中的数据和方法池中自定义的方法还能使用, 之后会进行注销组件和事件监听器的操作. 最后, 在destroyed()方法中, 已经拿不到数据. 最后进行销毁.

  1. beforeUpdate和updated在什么时候被调用
    beforeUpdate在监听到数据池数据变化的时候调用, 之后会将内存模板重新渲染页面上, 之后再调用updated()
  2. 在vue页面, 如果要从后端获取到商品列表, 在什么时候发出Ajax请求比较合适
    create()函数. 数据池,methods已经初始化, 内存模板还没被渲染. 这时拿到新数据后进行渲染, 马上可以看到最新的数据.
  3. 请手绘Vue实例的生命周期流程[简图]

🍋Vue2 Cli 脚手架

Vue Cli 是一个基于Vue.js进行快速开发的完整系统
官网文档: https://cli.vuejs.org/zh/

  • 为什么需要Vue Cli 脚手架?

目前开发模式的问题

  1. 开发效率低
  2. 不够规范
  3. 维护和升级, 可读性差

需求: 使用Vue脚手架进行模块化开发, 输入不同的url, 切换不同页面

🍋环境配置, 搭建项目

  1. 搭建Vue脚手架工程, 需要使用到NPM(node package manager), npm是随node.js安装的一款包管理工具, 类似于Maven. 所有要先安装Node.js
  2. 为了更好的兼容, 这里安装node.js 10.16.3.
  3. 如果以前安装过node.js, 为防止版本冲突, 先卸载之.
  4. 下载地址: https://nodejs.org/en/blog/release/v10.16.3 [网址进不去, 考虑连接手机热点]
    在这里插入图片描述
  5. 安装. 路径 不要有空格, 不要有中文. 比如:D:\program\nodejs10.16
    在这里插入图片描述
  6. 验证是否安装成功
    在这里插入图片描述如果看不到效果, 退出cmd, 重新开一个窗口测试即可
  7. 先删除以前的cli版本<不论是之前未下载或没有下载>
    npm uninstall vue-cli -g
  8. 安装淘宝镜像-cnpm
    npm install -g cnpm@7.1.1 --registry=https://registry.npm.taobao.org

    淘宝镜像已经更换域名
    修改npm至新的淘宝镜像源:
    npm config set registry http://registry.npmmirror.com
    查看npm源地址有没有换成功:
    npm config get registry
    通过配置淘宝镜像并安装使用cnpm
    npm install -g cnpm@7.1.1 --registry=https://registry.npmmirror.com

说明: npm 和 cnpm 的区别

  1. 两者之间只是node中包管理器的不同, 都可以使用
  2. npm是node官方的包管理器. cnpm是个中国版的npm, 是淘宝定制的 cnpm (gzip压缩支持)命令行工具, 代理默认的npm
  3. 如果因为网络原因无法使用npm下载, 那么这个cnpm就派上用场了
  4. 小结: npm和cnpm只是下载的地址不同, npm是从国外下载东西, cnpm是从国内下载东西
  1. 安装webpack和webpack-cli. 指令: npm install webpack@4.41.2 webpack-cli@4.9.2 -D
    这里指定了webpack的版本, webpack是一个打包工具
    报错执行: npm init --yes
  2. 安装脚手架 cnpm install -g @vue/cli@4.0.3
  3. 确认Vue-Cli 版本
    在这里插入图片描述
  4. 创建目录 D:\idea_project\zzw_vue_project, 并cmd到该目录
  5. 使用webpack创建vue脚手架项目
    vue init webpack vue_project_qs

可能会报的错误

  1. 运行: npm install -g @vue/cli-init
    在这里插入图片描述
  2. 如果出现了 downloading template…, 等待一分钟. 如果没有反应, 退出窗口, 重新来一次即可

在这里插入图片描述在这里插入图片描述在这里插入图片描述成功. 如果端口占用, vue会默认切换到另一个端口
如果报告端口占用的错误, 就把端口让出来, 重新运行命令
在这里插入图片描述在这里插入图片描述输入Ctrl + C 终止程序在这里插入图片描述

🍋IDEA配置项目

  1. 将Vue脚手架项目, 直接拖到IDEA, 就可以打开
    在这里插入图片描述
  2. 配置NPM
    在这里插入图片描述在这里插入图片描述启动
    在这里插入图片描述成功访问
    在这里插入图片描述

🍋vue项目结构分析

在这里插入图片描述

🍋项目执行流程

Vue请求页面执行流程
当我们输入http://localhost:8080, 看到的页面从何而来

在这里插入图片描述在这里插入图片描述

因为Vue默认生成的代码, 使用了很多简写, 造成了初学者理解困难.
整个页面渲染过程中, main.js是中心, 也是连接各个组件, 路由器的关键.
在这里插入图片描述

🍋路由器作业

题目一: 输入http://localhost:8080/#/hello, 返回
在这里插入图片描述配置自己的组件 HelloMary.vue

<template>
  <div>
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloMary",
  data() {//数据池
    return {
      msg: "HelloMary"
    }
  }
}
</script>

配置路由

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld.vue'

//@指的是src目录
import HelloMary from "@/components/HelloMary.vue"
import Zzw from "@/components/Zzw.vue"


Vue.use(Router)

export default new Router({
  routes: [ //路由表
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {//配置的一组路由
      path: '/hello',
      name: 'HelloMary',
      component: HelloMary
    }
  ]
})

题目二: 输入http://localhost:8080/#/
在这里插入图片描述

🍋路由器应用实例

配置自己的组件 Zzw.vue

<!--模板: 表示页面视图html-->
<template>
  <div>
    <h1>{{ msg }}</h1>
    <table>
      <tr>
        <td colspan="3">第1行第1列</td>
      </tr>
      <tr>
        <td rowspan="2">第2行第1列</td>
        <td>第2行第2列</td>
        <td>第2行第3列</td>
      </tr>
      <tr>
        <td>第3行第2列</td>
        <td>第3行第3列</td>
      </tr>
      <tr>
        <td rowspan="2">第4行第1列</td>
        <td>第4行第2列</td>
        <td>第4行第3列</td>
      </tr>
      <tr>
        <td>小猫咪<img src="@/assets/1.gif" width="100"></td>
        <td>第5行第3列</td>
      </tr>
    </table>
  </div>
</template>

<!--定义数据和操作方法, 默认导出-->
<script>
export default {
  name: "Zzw",
  data() {
    return {
      msg: "Welcome to Zzw!"
    }
  },
}
</script>

<!--
    样式,css 可以修饰页面视图
    0表示上下边距; auto表示左右居中
-->
<style scoped>
div {
  background-color: beige;
  width: 600px;
  margin: 0 auto;
}

table, td {
  border: solid red 1px;
  width: 600px;
  height: 50px;
  border-collapse: collapse; /*边界合并*/
}

h1 {
  color: red;
}
</style>

配置路由

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld.vue'

//@指的是src目录
import HelloMary from "@/components/HelloMary.vue"
import Zzw from "@/components/Zzw.vue"


Vue.use(Router)

export default new Router({
  routes: [ //路由表
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/hello',
      name: 'HelloMary',
      component: HelloMary
    },
    {//配置的一组路由
      path: "/zzw",
      name: "Zzw",
      component: Zzw
    }
  ]
})

App.vue 项目主体单页

<template>
  <div id="app">
    <!--<img src="./assets/logo.png">-->
    <!--将路由后的页面/视图, 引入到这里-->
    <router-view/>
  </div>
</template>

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

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

HelloMary.vue

<template>
  <div>
    <img src="@/assets/logo.png"/>
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: "HelloMary",
  data() {//数据池
    return {
      msg: "HelloMary"
    }
  }
}
</script>

<style scoped>

</style>

HelloWorld.vue

<template>
  <div class="hello">
    <img src="@/assets/logo.png"/>
    <h1>{{ msg1 }}</h1>
    <h2>{{ msg2 }}</h2>
    <a href="https://www.baidu.com" target="_blank">{{ msg3 }}</a>
  </div>
</template>

<script>
export default {//默认导出组件
  name: 'HelloWorld',
  data () {//数据池
    return {
      msg1: '网站首页-赵志伟',
      msg2: '网站首页-赵志伟',
      msg3: '点击进入百度'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

🍋ElementUI

基本说明

  1. ElementUI官网: https://element.eleme.cn/#/zh-CN
    vue2对应ElementUI.
    vue3对应ElementPlus
  2. ElementUI是组件库, 是网站快速成型的工具

🍋基本使用

在Vue2项目中, 使用ElementUI组件. Vue3使用ElementPlus

  1. 安装element-ui 组件库. cmd进入到项目, 指令 npm i element-ui@2.12.0
    在这里插入图片描述
  2. 在mian.js中引入ElementUI
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

🍋课后作业

如果自己的代码里有data数据池, methods, template, 那么只需引入data里的数据, methods里的方法和template里的代码即可

  1. 做出斑马纹表格
  2. 做出树形控件 - 描述产品分类菜单

🍋Axios

axios底层地址是promise promise讲解👉

基本说明

  1. axios是独立于vue的一个项目, 不是vue的一部分
  2. axios通常和Vue一起使用, 实现ajax操作
  3. Axios 是一个基于 promise 的HTTP库

学习文档: https://javasoho.com/axios/

🍋Axios库文件

  1. 使用axios需要引入axios库文件
  2. 可以直接引入
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  1. 也可以下载axios.min.js, 在本地引入
<script src="vue.js"></script>
<script src="axios.min.js"></script>

🍋 Axios应用实例

需求: 在Vue项目中使用Axios, 从服务器获取json数据, 显示在页面

创建一个JavaScript项目
在这里插入图片描述data/response.data.json

{
  "success": true,
  "message": "成功",
  "data": {
    "items": [
      {
        "name": "牛魔王",
        "age": 900
      },
      {
        "name": "红孩儿",
        "age": 400
      },
      {
        "name": "齐天大圣",
        "age": 890
      },
      {
        "name": "唐玄奘",
        "age": 80000
      }
    ]
  }
}

把vue.js库文件 和 axios.min.js库文件 拷贝到项目路径下
请求url在浏览器地址栏copy一下

<body>
<!--页面视图-->
<div id="app">
    <h1>{{msg}}</h1>
    <table border="1px" width="300px">
        <tr>
            <td>名字</td>
            <td>年龄</td>
        </tr>
        <tr v-for="monster in monsterList">
            <td>{{monster.name}}</td>
            <td>{{monster.age}}</td>
        </tr>
    </table>
</div>
<script src="vue.js"></script>
<script src="axios.min.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            msg: "妖怪信息列表",
            monsterList: [],//表示妖怪的信息数组
        },
        methods: {//定义方法
            list() {//发出ajax请求, 获取数据 axios
                /*
                解读
                1. axios.get() 表示发出ajax请求
                2. http://localhost:63342/axios/data/response.data.json 表示请求的是url
                   要根据实际情况来填写
                3. axios发出ajax请求的基本语法
                   axios.get(url).then(箭头函数).then(箭头函数)...catch(箭头函数)
                   (1)如果get请求成功就进入第一个then()
                   (2)可以在 第一个then()中处理成功回调的数据, 还可以继续发出axios的ajax请求
                   (3)如果有异常, 会进入到 catch(箭头函数)
                4. list方法在生命周期函数created() 中调用
                 */
                axios.get("http://localhost:63342/axios/data/response.data.json")
                    .then((responseData) => {
                        //要想准确拿到数据, 要一次一次的console.log()取
                        // console.log("responseData=", responseData);
                        // console.log("responseData.data=", responseData.data);
                        // console.log("responseData.data.data=", responseData.data.data);
                        console.log("responseData.data.data.items=", responseData.data.data.items);
                        //将妖怪列表数组信息, 绑定到data数据池的monsterList
                        //小技巧, 一定要学会看返回的数据格式
                        this.monsterList = responseData.data.data.items;
                        //可以再次发出ajax请求, 故意发出了第二次ajax请求
                        // return axios.get("http://localhost:63342/axios/data/response.data.json");
                    })
                    // .then(responseData => {
                    //     console.log("第二次ajax请求返回的数据 responseData.data.data.items=", responseData);
                    // })
                    .catch(err => {
                        console.log("异常=", err);

                    });
            },
        },
        created() {//生命周期函数
            this.list();
        },
    })
</script>
</body>

🍋注意事项和细节

将JSON对象转成字符串, 通过JSON.stringify(responseData)
格式化输出JSON字符串, 方便观察分析

//使用JSON.stringify(json), 把json对象转成字符串, 方便观察
console.log("responseData=", JSON.stringify(responseData));

在这里插入图片描述JSON字符串在线解析 https://www.json.cn/
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/750076.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

西门子S7300以太网模块labview软件介绍

借助捷米特ETH-S7300-JM01以太网模块&#xff0c;通过NetS7 OPC和NI OPC Servers&#xff0c;西门子S7-300与测控软件NI LABVIEW实现以太网通讯和监控。 功能简介 LabVIEW是一种程序开发环境&#xff0c;由美国国家仪器&#xff08;NzI&#xff09;公司研制开发&#xff0c;类…

Redis 宕机了,如何避免数据丢失?

前言 如果有人问你&#xff1a;"你会把 Redis 用在什么业务场景下&#xff1f;" 我想你大概率会说&#xff1a;"我会把它当作缓存使用&#xff0c;因为它把后端数据库中的数据存储在内存中&#xff0c;然后直接从内存中读取数据&#xff0c;响应速度会非常快。…

英华特在创业板上市:总市值约50亿元,国产品牌持续向上

7月13日&#xff0c;苏州英华特涡旋技术股份有限公司&#xff08;下称“英华特”&#xff0c;SZ:301272&#xff09;在深圳证券交易所创业板上市。本次上市&#xff0c;英华特的发行价为51.39元/股&#xff0c;发行数量为1463万股&#xff0c;募资总额约为7.52亿元&#xff0c;…

直播 | SDS 容灾方案,让制品数据更安全

近日&#xff0c;腾讯 CODING WePack 制品管理系统 V1 以及腾讯 CODING DevOps 研发效能管理平台 V7 与 XSKY 星辰天合的统一数据平台 XEDP 及天合翔宇分布式存储系统完成互相兼容认证&#xff0c;在数据层面满足了共同客户敏捷开发的高可用建设合规要求。 联合解决方案可以帮…

Linux stress命令---压力测试

一、使用场景 CPU压力测试 内存压力测试 磁盘IO测试 Swap可用性测试 二、语法及常用参数 stress [选项] [进程数] -?, --help&#xff1a;显示帮助信息 --version&#xff1a;显示版本信息 -v, --verbose&#xff1a;详细输出 -q, --quiet&#xff1a;静默输出 -t, --timeout&…

基于python 和anaconda搭建环境

目录 1.先了解以下几点。 2 方案&#xff1a;pycharmanaconda 3.基本步骤 4 熟悉anaconda。 4.1 虚拟环境的创建方法 4.2 anaconda prompt中&#xff0c;常用指令 4.3 在Anaconda Navigate中的一些操作 4.3.1给已有虚拟环境安装包 4.3.2 新建虚拟环境 4.4 在pycharm中…

JavaScript 深度剖析-函数式编程(一)

文章介绍 为什么要学习函数编程以及什么是函数式编程函数式编程的特性(纯函数、柯里化、函数组合等)函数式编程的应用场景函数式编程库 Lodash 为什么要学习函数式编程 函数式编程是非常古老的一个概念&#xff0c;早于第一台计算机的诞生&#xff0c;函数式编程的历史。 那…

灵活利用ChatAI,提升你的码力—程序员篇

前言 ChatGPT目前还完全无法替代程序员&#xff0c;尤其是在一些强上下文的编程场景下&#xff0c;比如一些重业务的编程场景&#xff0c;但是可以利用它来完成一些编程相关的事&#xff0c;把它当做一个工具来大幅度提升我们的工作效率 ​开发&#xff1a;微信小程序 用户交互…

pg手动清理pg_wal文件

1、由于我是docker安装的&#xff0c;要先进入docker容器 docker exec -it a470585a9cdc /bin/bash2、查看哪个检查点之前的日志可以清除 pg_controldata $PGDATA表示00000001000000E7000000CE之前的pg_wal文件可以删除 3、手动清理pg_wal pg_archivecleanup -d $PGDATA/pg…

当我掉入计算机的大坑中时,遇到简单的题也很吃力,这可如何是好呢?

一支笔&#xff0c;一双手&#xff0c;一道力扣&#xff08;Leetcode&#xff09;做一宿&#xff01;&#xff01;&#xff01; 一、分享自己相关的经历 我们可能经常听到这句话&#xff0c;人永远赚不到认知以外的钱&#xff0c;如果把它放到程序员行业来说&#xff0c;同样适…

微信加粉计数器后台开发

后台包括管理后台与代理后台两部分 管理后台 管理后台自带网络验证卡密系统,一个后台可以完成对Pc端的全部对接,可以自定义修改分组名称 分享等等代理后台 分享页 调用示例 <?php$request new HttpRequest(); $request->setUrl(http://xxxxxxx/api); $request->…

ROS:URDF、Gazebo与Rviz结合使用

目录 一、机器人运动控制以及里程计信息显示1.1ros_control 简介1.2运动控制实现流程(Gazebo)1.2.1为 joint 添加传动装置以及控制器1.2.2xacro文件集成1.2.3启动 gazebo并控制机器人运动 1.3Rviz查看里程计信息1.3.1启动 Rviz1.3.2添加组件 二、雷达信息仿真以及显示2.1流程分…

路径规划算法:基于人工兔优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于人工兔优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于人工兔优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法…

浮点数的近似保存与计算

这里写目录标题 负数的补码存储十进制浮点数与二进制的转换有限循环的二进制无限循环的二进制 计算机对浮点数的保存无限循环二进制数的保存浮点数的近似 参考文献 负数的补码存储 首先我们回忆一下负数的补码表示。我们都知道&#xff0c;有符号数的负数使用补码的方式进行存…

WVP+ZLMediaKit实现网络摄像头接入

​ 记录下本地调试监控摄像头相关信息。 参考来源&#xff1a;部署 WVPZLMediaKit 实现大华摄像头接入_wvp zlm_鬼畜的稀饭的博客-CSDN博客 ZLMediaKit 代码地址 WVP 代码地址 ⚠️ 摄像头需要连接PoE设备来供电&#xff08;插网线就能供电&#xff09; 资源清单&#xff1a…

如何通过设备管理系统实现设备全生命周期管理

设备是生产力的核心&#xff0c;对企业的运营和效益起着至关重要的作用。然而&#xff0c;随着设备数量和复杂性的增加&#xff0c;如何有效管理设备的全生命周期成为了一个挑战。 在这个时代&#xff0c;设备管理系统成为了一种重要的工具&#xff0c;帮助企业实现设备全生命周…

LJUBOMORA - 思维+二分

分析&#xff1a; 二分最小的嫉妒值&#xff0c;每次check需要判断每一种颜色需要分给几个小朋友&#xff0c;如果可以所有都分完那么返回true。 代码&#xff1a; #include <bits/stdc.h>using namespace std;typedef long long ll; typedef pair<int,int> pii;…

[QT编程系列-7]:C++图形用户界面编程,QT框架快速入门培训 - 3- QT窗体设计 - 自定义工具栏、状态栏、快捷键、图标

目录 3. QT窗体设计 3.2 自定义工具栏 3.2.1 目标 3.2.2 实现过程 3.2 自定义状态栏 3.2.1 目标 3.2.2 过程 3.3 自定义动作快捷键 3.4 自定义图标 3. QT窗体设计 3.2 自定义工具栏 在Qt中&#xff0c;ToolBar&#xff08;工具栏&#xff09;是一种常见的GUI元素&a…

【MEX】CF1629 C

Problem - C - Codeforces 题意&#xff1a; 思路&#xff1a; 模拟样例 可以发现做法是对该数列进行分段&#xff0c;当当前mex在后缀没有出现过时&#xff0c;形成一个区间[l,r] 然后有两个问题&#xff1a; 1.mex怎么去维护 2.怎么看mex在后缀有没有出现过 对于第一个…

提高Spark性能的关键:动态资源分配

前言 Spark提供了一种机制,可以根据工作负载动态调整应用程序占用的资源。这意味着,如果不再使用资源,应用程序可能会将资源返还给集群,并在以后有需求时再次请求这些资源。如果Spark集群中有多个应用程序共享资源,则此功能特别有用。 该功能在默认情况下被禁用,并且在…