草庐IT

day06-Vue03

liyuelian 2023-03-28 原文

Vue03

10.组件化编程

10.1基本说明

官网链接:https://v2.cn.vuejs.org/v2/guide/components-registration.html

  1. 在大型应用开发时,页面可以划分成很多部分。不同的页面,往往也会有相同的部分——例如可能会有相同的头部导航

  2. 如果每个页面都独自开发,无疑增加了我们的开发成本。因此,我们会把页面的不同部分拆分成独立的组件,然后在不同的页面共享这些组件,避免重复开发

    • 组件(Component)是Vue.js最强大的功能之一(组件提高了复用性:界面复用性和代码复用性)
    • 组件也是一个Vue实例,也包括:data,methods,生命周期函数等
    • 组件渲染需要html模板,所以增加了template属性,属性的值就是HTML模板
    • 对于全局组件,任何Vue实例都可以直接在HTML中通过组件名称来使用该组件
    • data在组件中是一个函数,不再是一个对象,这样每次引用组件都是独立的对象/数据

10.2应用实例

为什么需要组件化编程?

例子

现在希望实现一个功能:点击一个按钮,可以显示点击的次数。如果要求多个按钮都实现该功能呢?

10.2.1非组件化方式

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件化编程-普通方式</title>
</head>
<body>
<div id="app">
    <!--非组件化方式-普通方式-->
    <button v-on:click="count++">点击次数={{count}}次[非组件化方式]</button><br/>
    <!--
    1.如果需要多个按钮都实现同样的功能,直接粘贴复制是不可行的,
        因为这样的话按钮都绑定了同一个数据count,
        当其中一个按钮按下,其他按钮显示的数据也会跟着改变。
    2.我们现在的要求是:不同的按钮的数据应该分开计算,又该怎么实现?--可以在数据池中增加不同的属性
    -->
    <button v-on:click="count2 ++">点击次数={{count2}}次[非组件化方式]</button><br/>
    <!--3.但是新的问题又出现了,当又要增加多个同样功能的按钮时,怎么实现呢?
    仍然像之前一样,在数据池中不停地增加新的属性吗?-->
    <button v-on:click="count3 ++">点击次数={{count3}}次[非组件化方式]</button>
</div>
<script src="vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {//data数据池
            count: 0,
            count2: 0,
            count3: 0
        }
    })
</script>
</body>
</html>

如上所述,多个按钮的界面和业务功能都是类似的,但是我们都重新写了一次,代码复用性差,如果是在复杂的案例中,问题将会更加明显。解决方案就是——组件化编程。

10.2.2全局组件方式

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件化编程-全局组件</title>
</head>
<body>
<div id="app">
    <h1>组件化-全局组件</h1>
    <!--使用全局组件-->
    <!--vue解析时,会用模板template来替换这个"counter"标识-->
    <counter></counter><br/>
    <counter></counter><br/>
    <counter></counter>
</div>
<script src="vue.js"></script>
<script>
    // 1.定义一个全局组件,名为 counter
    // 2.{} 表示的就是 组件相关的内容
    // 3.template 用于指定该组件的界面,因为会引用到数据池的数据,所以使用模板字符串
    // 4.注意:要把组件视为Vue实例,也有自己的数据池和 方法 methods
    // 5.对于组件,我们的数据池数据是使用函数/方法返回的(目的是为了保证每一个组件的数据是独立的!),不能使用原来的方式
    // 6.这时我们就实现了 界面通过template实现共享,业务处理可以复用 的目的
    // 7.全局组件是属于所有的vue实例的,因此可以在任何一个vue实例中使用:
    //   例如当前页面中有一个vue实例,如果我们再声明几个vue实例,该全局组件都可以在这些vue实例中使用
    Vue.component("counter", {
        //组件渲染需要html模板,所以增加了template属性,值就是HTML模板
        template: `<button v-on:click="click()">点击次数={{count}}次[全局组件化方式]</button>`,
        data() {//注意和原来的方式不一样
            return {count: 0}
        },
        methods: {//方法可以共享,但data数据不能共享
            click() {
                this.count++;//每一个组件的this对象不同,因此同一个方法改变的是不同的count
            }
        }
    })

    //创建vue实例,必须有
    let vm = new Vue({
        el: "#app"
    })
</script>
</body>
</html>

10.2.3局部组件方式

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>组件化编程-局部组件</title>
</head>
<body>
<div id="app">
    <h1>组件化-局部组件</h1>
    <!--使用局部组件,该组件是从 被挂载到 div(id=app)的vue实例中来的-->
    <my_counter></my_counter><br/>
    <my_counter></my_counter><br/>
    <my_counter></my_counter>
</div>
<script src="vue.js"></script>
<script>
    //定义一个组件 buttonCounter
    // 可以把常用的组件定义在js文件中(export),如果某个页面需要使用,直接import引入即可
    const buttonCounter = {
        template: `<button v-on:click="click()">点击次数={{count}}次[局部组件化方式]</button>`,
        data() {
            return {count: 0}
        },
        methods: {
            click() {
                this.count++;
            }
        }
    }

    //创建vue实例,必须有
    let vm = new Vue({
        el: "#app",
        components: {//引入某个组件,此时该组件就是一个局部组件,该组件的使用范围只在当前的vue实例中
            "my_counter":buttonCounter
        }
    })
    
    // 如果新创建了一个vue实例,挂载到一个div中(id="app2"),在该div中如果要使用局部组件
    // 也必须在该vue实例中引入该组件,否则div((id="app2")无法使用该局部组件
</script>
</body>
</html>

10.2.4全局组件VS局部组件

  1. 全局组件是属于所有的vue实例的,因此可以在任何一个vue实例中使用。

    例如当前页面中有一个vue实例,如果我们再声明几个vue实例,该全局组件都可以在这些vue实例中使用

  2. 局部组件的使用范围只在当前的vue实例中。

    例如:如果新创建了一个vue实例,挂载到一个新的div中(如:id="app2"),在div中如果要使用局部组件,也必须在新的vue实例中引入该组件,否则该div中无法使用该局部组件

  3. 组件定义需要放在new Vue()前,否则组件引入/注册会失效

10.3组件化小结

  • 组件也是一个Vue实例,它的定义也包括:data,methods,生命周期函数等
  • data在组件中是一个函数,不再是一个对象,这样每次引用组件都是独立的对象
  • 组件渲染需要html模板,所以增加了template属性,属性的值就是HTML模板

11.生命周期和钩子函数

官网:https://v2.cn.vuejs.org/v2/guide/instance.html

11.1基本说明

  1. Vue实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂载DOM、渲染-更新-渲染、卸载等一系列过程,我们称之为Vue实例的生命周期
  2. 钩子函数(监听函数/生命周期函数):Vue实例在完整的生命周期过程中(比如设置数据监听,编译模板,将实例挂载到DOM,在数据变化时更新DOM等),会自动触发钩子函数
  3. 钩子函数的作用:在某个阶段,给程序员一个做某些处理的机会
  4. Vue的生命周期非常重要,Vue编程模型都是建立在此基础上

11.2Vue实例的生命周期

  1. new Vue()

    创建了一个Vue的实例对象,此时就会进入组件的创建过程

  2. Init Events & Lifecycle

    初始化组件的事件和生命周期函数

  3. beforeCreate

    组件创建之后遇到的第一个生命周期函数,这个阶段data和methods以及dom结构都未被初始化,也就是获取不到data的值,不能调用methods中的方法

  4. Init injections & reactivity

    这个阶段中,正在初始化data和methods中的方法

  5. created

    这个阶段组件的data和methods中的方法已经初始化结束,可以访问,但是dom结构未初始化,页面未渲染

    此阶段适合发起ajax请求,因为模板的数据未渲染

  6. 编译模板结构(在内存中)

  7. beforeMount

    当模板在内存中编译完成,此时内存中的模板结构还未渲染至页面上,看不到真实的数据

  8. Create vm.$el and replace 'el' with it

    在把内存中渲染好的模板结构替换至真实的dom结构,也就是页面上

  9. mounted

    此时页面渲染好,用户看到的是真实的页面数据,生命周期创建阶段完毕,进入到了运行中的阶段

  10. 生命周期运行中

    1)beforeUpdate:当执行此函数,数据池的数据是新的,但页面是旧的

    2)Virtual DOM re-render and patch:根据最新的data数据,重新渲染内存中的模板结构,并把渲染好的模 板结构替换至页面

    3)updated:页面已经完成了更新,此时data数据和页面的数据都是新的

  11. beforeDestroy

    当执行此函数时,组件即将被销毁,但是还没有真正开始销毁,此时组件的data,methods方法还可以被调用

  12. Teardown

    注销组件和事件监听

  13. destroyed

    组件已经完成了销毁


11.3应用实例

需求:展示Vue实例的生命周期和钩子函数执行时机

  1. 重点研究几个重要的钩子函数(监听函数/生命周期函数):beforeCreate,created,beforeMount,mounted,beforeUpdate,updated
  2. 在这几个钩子函数中,数据模型是否加载/使用?自定义方法是否加载/可用?html模板(页面dom)是否加载/使用?html模板是否完成渲染(数据有没有被渲染)?

例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue生命周期和钩子函数</title>
</head>
<body>
<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("数据模型/数据池的数据是否加载/使用[no]?", this.name, " ", this.num);//undefined   undefined
            //[Vue warn]: Error in beforeCreate hook: "TypeError: this.show is not a function"
            //console.log("自定义方法是否加载/使用[no]?", this.show());
            console.log("用户页面dom(html模板)是否加载/使用[yes]?", document.getElementById("num"));//<span id="num">
            //{{num}} 拿到的是原生的插值表达式
            console.log("用户页面dom是否被渲染[no]?", document.getElementById("num").innerText);
        },
        created() {//生命周期函数-创建Vue实例
            console.log("==========created==========");
            console.log("数据模型/数据池的数据是否加载/使用[yes]?", this.name, " ", this.num);//Kristina   0
            console.log("自定义方法是否加载/使用[yes]?", this.show());//Kristina
            console.log("用户页面dom(html模板)是否加载/使用[yes]?", document.getElementById("num"));//<span id="num">
            //{{num}} 拿到的仍然是原生的插值表达式
            console.log("用户页面dom是否被渲染[no]?", document.getElementById("num").innerText);

            //这里因为已经可以使用数据池和自定义方法,因此可发出ajax请求,接收服务端的数据,然后再次更新data数据池
            //因此可以在内存模板编译之前准备好显示的数据
            //从而达到这样的效果:能够让用户看到最新返回的数据
        },
        beforeMount() {//生命周期函数-挂载前:完成内存模板编译,但还未渲染
            console.log("========beforeMount========");
            console.log("数据模型/数据池的数据是否加载/使用[yes]?", this.name, " ", this.num);//Kristina   0
            console.log("自定义方法是否加载/使用[yes]?", this.show());//Kristina
            console.log("用户页面dom(html模板)是否加载/使用[yes]?", document.getElementById("num"));//<span id="num">
            //{{num}} 拿到的仍然是原生的插值表达式
            console.log("用户页面dom是否被渲染[no]?", document.getElementById("num").innerText);
        },
        mounted() {//生命周期函数-挂载后
            console.log("==========mounted==========");
            console.log("数据模型/数据池的数据是否加载/使用[yes]?", this.name, " ", this.num);//Kristina   0
            console.log("自定义方法是否加载/使用[yes]?", this.show());//Kristina
            console.log("用户页面dom(html模板)是否加载/使用[yes]?", document.getElementById("num"));//<span id="num">
            console.log("用户页面dom是否被渲染[yes]?", document.getElementById("num").innerText);//0
        },
        beforeUpdate() {//生命周期函数-数据池数据更新前(只有在数据变化时会调用)
            console.log("==========beforeUpdate==========");
            console.log("数据模型/数据池的数据是否加载/使用[yes]?", this.name, " ", this.num);//Kristina   1
            console.log("自定义方法是否加载/使用[yes]?", this.show());//Kristina
            console.log("用户页面dom(html模板)是否加载/使用[yes]?", document.getElementById("num"));//<span id="num">
            //点击按钮,数据池中的num数据变为1,但这里仍然显示0,因为更新的数据还在内存模板中,没有被渲染到页面dom
            console.log("用户页面dom是否被更新[no]?", document.getElementById("num").innerText);//0
        },
        updated() {//生命周期函数-数据池数据更新后(只有在数据变化时会调用)
            console.log("=========updated=========");
            console.log("数据模型/数据池的数据是否加载/使用[yes]?", this.name, " ", this.num);//Kristina   1
            console.log("自定义方法是否加载/使用[yes]?", this.show());//Kristina
            console.log("用户页面dom(html模板)是否加载/使用[yes]?", document.getElementById("num"));//<span id="num">
            //页面dom重新被渲染
            console.log("用户页面dom是否被更新[yes]?", document.getElementById("num").innerText);//1
        }
    })
</script>
</body>
</html>

刷新页面时被调用的生命周期函数:

点击按钮后(数据变化后)被调用的函数:

11.4练习

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

    答:Vue的生命周期主要分为

    • 开始创建
    • 初始化事件和生命周期函数
    • beforeCreate()
    • 加载数据池和自定义方法
    • created()
    • 在内存中加载html模板(dom页面),编译模板
    • beforeMount()
    • 渲染数据
    • mounted()
    • 监听数据变化(循环)
      • beforeUpdate()
      • 重新在内存中渲染l模板,替换到页面dom结构中
      • updated()
    • beforeDestroy()
    • 注销组件和监听器等
    • destroyed(),实例销毁
  2. beforeUpdate()和updated()在什么时候被调用

    答:数据发生变化时被调用。数据变化有可能是来自后端数据的更新,或者用户操作导致的数据更新。

  3. 在vue页面,如果要从后端获取到商品列表,在什么时机发出ajax请求比较合适,为什么?

    答:在created()函数被调用时发出ajax请求比较合适。

    因为此时vue实例的data数据池和methods中的自定义函数都已经可以使用,但是未渲染页面dom。此时发出请求,可以拿到最新的数据,让用户直接看到最新的数据,无需在后面的流程中重新渲染。

  4. 请手绘Vue实例的生命周期流程(简图)

有关day06-Vue03的更多相关文章

  1. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  2. ruby-on-rails - rails : Find tasks that were created on a certain day? - 2

    我有一个任务列表(名称、starts_at),我试图在每日View中显示它们(就像iCal)。deftodays_tasks(day)Task.find(:all,:conditions=>["starts_atbetween?and?",day.beginning,day.ending]end我不知道如何将Time.now(例如“2009-04-1210:00:00”)动态转换为一天的开始(和结束),以便进行比较。 最佳答案 deftodays_tasks(now=Time.now)Task.find(:all,:conditio

  3. (附源码)vue3.0+.NET6实现聊天室(实时聊天SignalR) - 2

    参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍  介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。  内容有:    ①:Hub模型的方法介绍    ②:服务器端代码介绍    ③:前端vue3安装并调用后端方法    ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke()  去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on

  4. 什么是0day漏洞?如何预防0day攻击? - 2

    什么是0day漏洞?0day漏洞,是指已经被发现,但是还未被公开,同时官方还没有相关补丁的漏洞;通俗的讲,就是除了黑客,没人知道他的存在,其往往具有很大的突发性、破坏性、致命性。0day漏洞之所以称为0day,正是因为其补丁永远晚于攻击。所以攻击者利用0day漏洞攻击的成功率极高,往往可以达到目的并全身而退,而防守方却一无所知,只有在漏洞公布之后,才后知后觉,却为时已晚。“后知后觉、反应迟钝”就是当前安全防护面对0day攻击的真实写照!为了方便大家理解,中科三方为大家梳理当前安全防护模式下,一个漏洞从发现到解决的三个时间节点:T0:此时漏洞即0day漏洞,是已经被发现,还未被公开,官方还没有相

  5. ruby - Rails 比较 date.end_of_day.to_datetime 和 date.to_datetime.end_of_day 返回的日期对象值时返回 false - 2

    ruby1.9.3dev(2011-09-23修订版33323)[i686-linux]轨道3.0.20最近为什么在与DateTimeonRails相关的RSpecs项目上工作我发现在给定日期以下语句发出的值date.end_of_day.to_datetime和date.to_datetime.end_of_day虽然它们表示相同的日期时间,但比较时返回false。为了确认这一点,我打开了Rails控制台并尝试了以下操作1.9.3dev:053>monday=Time.now.monday=>2013-02-2500:00:00+05301.9.3dev:054>monday.cla

  6. vue 实现内容超出两行显示展开更多功能,可依据需求自定义任意行数! - 2

    平时开发中我们经常会遇到这样的需求,在一个不限高度的盒子中会有很多内容,如果全部显示用户体验会非常不好,所以可以先折叠起来,当内容达到一定高度时,显示展开更多按钮,点击即可显示全部内容,先来看看效果图: 这样做用户体验瞬间得到提升,接下来看看具体细节。0">主要操作在内容这里{{item.username}},……展开更多样式大家可依据自己项目需求进行设计,这里就不贴了,主要说几个关键的。1、在data中定义三个属性isShowMore:false, //控制展开更多的显示与隐藏textHeight:null, //框中内容的高度status:false, //内容状态是否打开2.计算内容是否

  7. vue3.0 + vite2.0+如何兼容低版本浏览器 - 2

    这里写自定义目录标题一、问题二、解决三、解决方案四、打包预览一、问题在使用vue3.2和vite2开发一个移动端或者钉钉端H5微服务iosapp内置浏览器打开没问题安卓app内置浏览器打开空白页面vconsole打印出现报错globalthisundefind二、解决内置浏览器版本比较低打印出来是63vue3代码不兼容低版本浏览器三、解决方案步骤一:vite.config.ts里build.target配置项指定构建目标为es2015或者步骤二:安装@vitejs/plugin-legacy安装完报错也还在指定版本可以解决“@vitejs/plugin-legacy”:“1.8.0”,步骤三:

  8. Ruby,从 Date.day_fraction_to_time 获取小时、秒和时间 - 2

    我找到了这个方法here.start=DateTime.nowsleep15stop=DateTime.now#minutesputs((stop-start)*24*60).to_ihours,minutes,seconds,frac=Date.day_fraction_to_time(stop-start)我有以下错误:`':privatemethod`day_fraction_to_time'calledforDate:Class(NoMethodError)我检查了/usr/lib/ruby/1.9.1/date.rb并找到了它:defday_fraction_to_time(

  9. ruby-on-rails - Rails 未定义方法 `strftime' 为 "2013-03-06":String - 2

    我遇到了错误“2013-03-06”的未定义方法`strftime':String当尝试使用strftime从字符串2013-03-06正常显示日期(2013年6月3日或类似日期)时。在我的index.html.erb中执行此操作的行看起来像这样我只是在学习Rails,所以我确信这只是一个愚蠢的初学者错误,我们将不胜感激。谢谢 最佳答案 当strftime是时间/日期类的方法时,您的截止日期看起来是一个字符串。你可以试试这个:Date.parse(task.duedate).strftime("%B%e,%Y")

  10. Vue3的新特性 - 2

    Vue3的新特性包括:CompositionAPI:一种新的API风格,可将有关组件功能的代码逻辑封装在单独的函数中,从而更好地管理和重用代码。Teleport:可以让组件在DOM层次结构中的任何位置渲染。Suspense:一种新的异步渲染模式,可以优化应用程序的性能。更快的渲染速度:Vue3使用了新的虚拟DOM算法,并且对渲染过程进行了优化,因此在渲染大型应用时性能更高。更小的包大小:Vue3的打包大小比Vue2更小,因为它不再需要依赖像vue-template-compiler这样的工具。其他改进:Vue3还具有其他一些改进,例如更好的TypeScript支持、更好的错误提示和更好的调试工

随机推荐