Shinkai005

V1

2022/05/25阅读:63主题:红绯

尚硅谷Vue2.0+Vue3.0全套教程-笔记48-59

整体笔记48-59.md

048-引出生命周期

代码:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>引出生命周期</title>
  <!-- 引入Vue -->
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>

  <!-- 准备好一个容器-->
  <div id="root">
   <h2 v-if="a">你好啊</h2>
   <h2 :style="{opacity}">欢迎学习Vue</h2>
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
  
   new Vue({
   el:'#root',
   data:{
    a:false,
    opacity:1
   },
   methods: {
    
   },
   //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
   mounted(){
    console.log('mounted',this)
    setInterval(() => {
     this.opacity -= 0.01
     if(this.opacity <= 0this.opacity = 1
    },16)
   },
  })

  //通过外部的定时器实现(不推荐)
  /* setInterval(() => {
   vm.opacity -= 0.01
   if(vm.opacity <= 0) vm.opacity = 1
  },16) */

 
</script>
</html>
  • 尽量把所有的逻辑代码都写到options里, 这也是看程序员水平的~

  • {opacity:opacity} ES6对象简写满足key:value同名 可以写成{opacity}

  • 真正开发很少用const vm 只是为了调试用

致命bug

vue排坑bug
vue排坑bug

这个错误虽然基本不会犯,但是初学还没有形成知识体系的时候还是可能会这么思考的~

首先, change()在没有返回值的时候会返回undefined,undefined在插值语法里不会显示.因此,初学者会认为这么写刚好满足刚进来就执行的要求.

但是, 实际上一定要考虑的一点是, 任何地点修改data里的值都会引起模板重现解析,(不能用重新渲染 了哦,因为不一定)

因此, 就会出现不停地开定时器的情况,最后卡死界面

说个心得 : 我在写算法的时候经常会出现自己把自己写死的情况,一般这个时候就得重头捋了,不要从当前步骤往前捋....切记切记.很可能是思路就违反了某些原则,而不是单单的在编码过程中写错了.

mounted 类似window.onload只会调用一次. 永远只会调用一次~新的dom元素渲染叫做update

笔记

  <!-- 
    生命周期:
      1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
      2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
      3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
      4.生命周期函数中的this指向是vm 或 组件实例对象。
  -->

049-生命周期_挂载流程

代码:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>分析生命周期</title>
  <!-- 引入Vue -->
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>
  <!-- 准备好一个容器-->
  <div id="root" :x="n">
   <h2 v-text="n"></h2>
   <h2>当前的n值是:{{n}}</h2>
   <button @click="add">点我n+1</button>
   <button @click="bye">点我销毁vm</button>
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

  new Vue({
   el:'#root',
   // template:`
   //  <div>
   //   <h2>当前的n值是:{{n}}</h2>
   //   <button @click="add">点我n+1</button>
   //  </div>
   // `,
   data:{
    n:1
   },
   methods: {
    add(){
     console.log('add')
     this.n++
    },
    bye(){
     console.log('bye')
     this.$destroy()
    }
   },
   watch:{
    n(){
     console.log('n变了')
    }
   },
   beforeCreate() {
    console.log('beforeCreate')
   },
   created() {
    console.log('created')
   },
   beforeMount() {
    console.log('beforeMount')
   },
   mounted() {
    console.log('mounted')
   },
   beforeUpdate() {
    console.log('beforeUpdate')
   },
   updated() {
    console.log('updated')
   },
   beforeDestroy() {
    console.log('beforeDestroy')
   },
   destroyed() {
    console.log('destroyed')
   },
  })
 
</script>
</html>
image-20220524191601351
image-20220524191601351

有几个注意的点:

  • beforeMount: 这个阶段虚拟dom已经生成好了,只不过没替换真实dom
image-20220524193225162
image-20220524193225162
  • vm.$el存了一份虚拟dom,用其替换el内容

  • beforeMounted期间对dom所有的操作都不会产生最终效果

  • 一般在mounted阶段,进行一些初始化操作,开启定时器,发送网络请求,订阅信息,绑定自定义事件等

  • template的作用其实和el一样, 如果不在界面上写就写到template里. 这个模板会编译到render函数里

050-生命周期_更新流程

  • vue2.x 不能用template做根标签~
  • 如何判断一个元素是不是dom元素 sth. instanceof HTMLElement
  • beforeUpdate 数据已经更新但是没有渲染到页面上
  • updated数据和页面都是新的,保持同步

051-生命周期_销毁流程

destroy vue3没了..

  • beforeDestroy 一般先把初始化的东西全部都销毁
  • destroyed 结束 vm带的组件,事件监听, watcher也没了

老规矩不写了吧?

052-生命周期_总结

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>引出生命周期</title>
  <!-- 引入Vue -->
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>
  <!-- 准备好一个容器-->
  <div id="root">
   <h2 :style="{opacity}">欢迎学习Vue</h2>
   <button @click="opacity = 1">透明度设置为1</button>
   <button @click="stop">点我停止变换</button>
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

   new Vue({
   el:'#root',
   data:{
    opacity:1
   },
   methods: {
    stop(){
     this.$destroy()
    }
   },
   //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
   mounted(){
    console.log('mounted',this)
    this.timer = setInterval(() => {
     console.log('setInterval')
     this.opacity -= 0.01
     if(this.opacity <= 0this.opacity = 1
    },16)
   },
   beforeDestroy() {
    clearInterval(this.timer)
    console.log('vm即将驾鹤西游了')
   },
  })

 
</script>
</html>

vue优化小技巧

image-20220524231658788
image-20220524231658788

在不同局部作用域要用同一个非data内数据的时候, 可以直接把其写到vm的属性上,这里是this.id上~

image-20220524231828720
image-20220524231828720

尽量别用 id, timer什么的更好

笔记

 <!-- 
   常用的生命周期钩子:
     1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
     2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

   关于销毁Vue实例
     1.销毁后借助Vue开发者工具看不到任何信息。
     2.销毁后自定义事件会失效,但原生DOM事件依然有效。
     3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
 -->

还有一个点要注意,算是vue优化技巧,即使是一句话方法也不要在模板里写,例如

@click = "clearInterval(timer)"

尽量写成 @click = "stop"

methods:{stop(){clearInterval(timer)}}

053-对组件的理解

我的笔记追求理解, 尽量别记. 背一些东西只是为了更好理解~

所以理解组件为什么会产生是很重要的

image-20220525130719428
image-20220525130719428

这里是习惯比较好的,并且比较好维护的编写原生h5项目的方式方法.

  • 将页面划分区域,然后用不同的css和js去控制每一个区域
image-20220525130835562
image-20220525130835562

这种情况下,如果又多了一个html文件,复用顶部和底部应该怎么做?

  • 把前一个html文件里内容CV一份
  • 然后引入对应的cssjs文件
image-20220525131001247
image-20220525131001247
  • 然后将新的区域生成对应的css和js.最后这个图就变成了这样
image-20220525131042700
image-20220525131042700

画结构图都不好画~

带来的缺陷就是,没办法复用,依赖混乱不好维护.

  • 说直白点,不符合程序员的"懒"/"勤奋",程序员的懒和勤奋都是基于一劳永逸的~写一次能用就用.

这个时候是不是可以很容易的思考出, 把html+css+js结合在一起不就好了?用哪个位置引入那个位置不就可以了?

伟大的想法其实懂了思考的过程真没那么伟大.记得小学的课文..伟人也是人

大佬的想法可能思维跳跃的很严重,但是自己在前人的肩膀上把思维补全,让思维连续起来,就很容易理解了.

这就是组件思想

image-20220525131500415
image-20220525131500415

如今我们的代码就成了这个样子~是不是舒服多了?

其实vue2.x的代码层面依旧不是那么的整齐,vue3做了改变.很舒服

下面就是如今的组件复用~

image-20220525131607586
image-20220525131607586
image-20220525133805466
image-20220525133805466

054-非单文件组件

代码

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>基本使用</title>
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>
  <!-- 准备好一个容器-->
  <div id="root">
   <hello></hello>
   <hr>
   <h1>{{msg}}</h1>
   <hr>
   <!-- 第三步:编写组件标签 -->
   <school></school>
   <hr>
   <!-- 第三步:编写组件标签 -->
   <student></student>
  </div>

  <div id="root2">
   <hello></hello>
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false

  //第一步:创建school组件
  const school = Vue.extend({
   template:`
    <div class="demo">
     <h2>学校名称:{{schoolName}}</h2>
     <h2>学校地址:{{address}}</h2>
     <button @click="showName">点我提示学校名</button> 
    </div>
   `
,
   // el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
   data(){
    return {
     schoolName:'尚硅谷',
     address:'北京昌平'
    }
   },
   methods: {
    showName(){
     alert(this.schoolName)
    }
   },
  })

  //第一步:创建student组件
  const student = Vue.extend({
   template:`
    <div>
     <h2>学生姓名:{{studentName}}</h2>
     <h2>学生年龄:{{age}}</h2>
    </div>
   `
,
   data(){
    return {
     studentName:'张三',
     age:18
    }
   }
  })
  
  //第一步:创建hello组件
  const hello = Vue.extend({
   template:`
    <div> 
     <h2>你好啊!{{name}}</h2>
    </div>
   `
,
   data(){
    return {
     name:'Tom'
    }
   }
  })
  
  //第二步:全局注册组件
  Vue.component('hello',hello)

  //创建vm
  new Vue({
   el:'#root',
   data:{
    msg:'你好啊!'
   },
   //第二步:注册组件(局部注册)
   components:{
    school,
    student
   }
  })

  new Vue({
   el:'#root2',
  })
 
</script>
</html>

注意点:

  • 主要就是data方法要返回一个对象了,不直接写成一个data对象了

笔记

 <!-- 
  Vue中使用组件的三大步骤:
    一、定义组件(创建组件)
    二、注册组件
    三、使用组件(写组件标签)

  一、如何定义一个组件?
     使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
     区别如下:
       1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
       2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
     备注:使用template可以配置组件结构。

  二、如何注册组件?
      1.局部注册:靠new Vue的时候传入components选项
      2.全局注册:靠Vue.component('组件名',组件)

  三、编写组件标签:
      <school></school>
 -->

055-组件的几个注意点

代码:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>几个注意点</title>
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>

  <!-- 准备好一个容器-->
  <div id="root">
   <h1>{{msg}}</h1>
   <school></school>
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false
  
  //定义组件
  const s = Vue.extend({
   name:'atguigu',
   template:`
    <div>
     <h2>学校名称:{{name}}</h2> 
     <h2>学校地址:{{address}}</h2> 
    </div>
   `
,
   data(){
    return {
     name:'尚硅谷',
     address:'北京'
    }
   }
  })

  new Vue({
   el:'#root',
   data:{
    msg:'欢迎学习Vue!'
   },
   components:{
    school:s
   }
  })
 
</script>
</html>
image-20220525154835776
image-20220525154835776
  • 组件名用大驼峰比较好~首字母大写
  • 多单词的就全小写中间用短横-
  • 注意 在脚手架编译下才可以大驼峰写, image-20220525155140222

不然报错,报错是找不到myschool,html本身大小写不敏感都会变成小写.

我试了下,大致就是短横线和首字母大写的形式vue源码里写了能修改,但是大驼峰形式源码里没有~so没有啥用

  • 还有个注意这里,name属性,如果有name属性,他会把value值拿来做元素名的,而不是自己注册的xuexiao
    • 一般是第三方组件库和大型项目也会用这种方式避免命名冲突
image-20220525161817435
image-20220525161817435
  • 而且自定义组件可以写自闭合标签 也就是 <xuexiao/>这样.但是只能在脚手架里用
  • image-20220525163731597
    image-20220525163731597
  • Vue.extend 可以不写的 直接传一个对象就好,vue在components里会传入Vue.extend

笔记

 <!-- 
  几个注意点:
    1.关于组件名:
       一个单词组成:
          第一种写法(首字母小写):school
          第二种写法(首字母大写):School
       多个单词组成:
          第一种写法(kebab-case命名):my-school
          第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
       备注:
         (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
         (2).可以使用name配置项指定组件在开发者工具中呈现的名字。

    2.关于组件标签:
       第一种写法:<school></school>
       第二种写法:<school/>
       备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

    3.一个简写方式:
       const school = Vue.extend(options) 可简写为:const school = options
 -->

056-组件的嵌套

代码:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>组件的嵌套</title>
  <!-- 引入Vue -->
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>
  <!-- 准备好一个容器-->
  <div id="root">
   
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

  //定义student组件
  const student = Vue.extend({
   name:'student',
   template:`
    <div>
     <h2>学生姓名:{{name}}</h2> 
     <h2>学生年龄:{{age}}</h2> 
    </div>
   `
,
   data(){
    return {
     name:'尚硅谷',
     age:18
    }
   }
  })
  
  //定义school组件
  const school = Vue.extend({
   name:'school',
   template:`
    <div>
     <h2>学校名称:{{name}}</h2> 
     <h2>学校地址:{{address}}</h2> 
     <student></student>
    </div>
   `
,
   data(){
    return {
     name:'尚硅谷',
     address:'北京'
    }
   },
   //注册组件(局部)
   components:{
    student
   }
  })

  //定义hello组件
  const hello = Vue.extend({
   template:`<h1>{{msg}}</h1>`,
   data(){
    return {
     msg:'欢迎来到尚硅谷学习!'
    }
   }
  })
  
  //定义app组件
  const app = Vue.extend({
   template:`
    <div> 
     <hello></hello>
     <school></school>
    </div>
   `
,
   components:{
    school,
    hello
   }
  })

  //创建vm
  new Vue({
   template:'<app></app>',
   el:'#root',
   //注册组件(局部)
   components:{app}
  })
 
</script>
</html>
image-20220525164459864
image-20220525164459864

注册给谁在谁的template里写

学组件嵌套尽量用vue开发者工具,看原生dom结构看不到嵌套的关系

image-20220525165128475
image-20220525165128475

一般用app来管理所有组件.标准化开发必要的

讲的真好, 把很多工程化东西开始讲了

标准化开发
标准化开发

057-VueComponent构造函数

代码:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>VueComponent</title>
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>

  <!-- 准备好一个容器-->
  <div id="root">
   <school></school>
   <hello></hello>
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false
  
  //定义school组件
  const school = Vue.extend({
   name:'school',
   template:`
    <div>
     <h2>学校名称:{{name}}</h2> 
     <h2>学校地址:{{address}}</h2> 
     <button @click="showName">点我提示学校名</button>
    </div>
   `
,
   data(){
    return {
     name:'尚硅谷',
     address:'北京'
    }
   },
   methods: {
    showName(){
     console.log('showName',this)
    }
   },
  })

  const test = Vue.extend({
   template:`<span>atguigu</span>`
  })

  //定义hello组件
  const hello = Vue.extend({
   template:`
    <div>
     <h2>{{msg}}</h2>
     <test></test> 
    </div>
   `
,
   data(){
    return {
     msg:'你好啊!'
    }
   },
   components:{test}
  })


  // console.log('@',school)
  // console.log('#',hello)

  //创建vm
  const vm = new Vue({
   el:'#root',
   components:{school,hello}
  })
 
</script>
</html>
  • 打印一下组件console.log(student)
image-20220525170547985
image-20220525170547985

那么如何判断这个构造函数是否被调用呢?

可以找到源码中的位置打一个断点或者console.log一下

笔记

 <!-- 
  关于VueComponent:
     1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

     2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,
      即Vue帮我们执行的:new VueComponent(options)。

     3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

     4.关于this指向:
       (1).组件配置中:
          data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
       (2).new Vue(options)配置中:
          data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

     5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
      Vue的实例对象,以后简称vm。
 -->

特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

事件总线会用到,一定要记住这个

058-Vue实例与组件实例

vm 和 vc的区别

  • 首先vm为什么叫vm? vc为什么叫vc?

    • mvvm model view viewmodel VC vuecomponent
  • vc不能写el

  • vc里data只能写函数式并且返回一个对象

    image-20220525183050011
    image-20220525183050011

059-一个重要的内置关系

代码:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8" />
  <title>一个重要的内置关系</title>
  <!-- 引入Vue -->
  <script type="text/javascript" src="../js/vue.js"></script>
 </head>
 <body>

  <!-- 准备好一个容器-->
  <div id="root">
   <school></school>
  </div>
 </body>

 <script type="text/javascript">
  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
  Vue.prototype.x = 99

  //定义school组件
  const school = Vue.extend({
   name:'school',
   template:`
    <div>
     <h2>学校名称:{{name}}</h2> 
     <h2>学校地址:{{address}}</h2> 
     <button @click="showX">点我输出x</button>
    </div>
   `
,
   data(){
    return {
     name:'尚硅谷',
     address:'北京'
    }
   },
   methods: {
    showX(){
     console.log(this.x)
    }
   },
  })

  //创建一个vm
  const vm = new Vue({
   el:'#root',
   data:{
    msg:'你好'
   },
   components:{school}
  })

  
  //定义一个构造函数
  /* function Demo(){
   this.a = 1
   this.b = 2
  }
  //创建一个Demo的实例对象
  const d = new Demo()

  console.log(Demo.prototype) //显示原型属性

  console.log(d.__proto__) //隐式原型属性

  console.log(Demo.prototype === d.__proto__)

  //程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
  Demo.prototype.x = 99

  console.log('@',d) */


 
</script>
</html>

小补一波原型哦~ const tom = new People()

  • tom._proto_ === People.prototype

    image-20220525234502299
    image-20220525234502299
  • prototype 和 写在自身上区别?

    • prototype是引用类型. 所有的vm共同的prototype~也就是找到的是同一个
    • 自身上 每一个vm上的data methods等不一样~
    image-20220525234929991
    image-20220525234929991

    这个基础好一些的应该直接能看懂~就是 VC的原型对象的\__proto__从object的原型对象连到了vm的原型对象上了.

笔记

 <!-- 
   1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
   2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
 -->

附录

vue中template如何自动补全双标签?

image-20220525175109233
image-20220525175109233
image-20220525175055458
image-20220525175055458
image-20220525175022609
image-20220525175022609
  /* 自动补全模板字符串 */ 

  "emmet.triggerExpansionOnTab"true,

  "emmet.showAbbreviationSuggestions"true,

  "emmet.showExpandedAbbreviation""always",

  "emmet.includeLanguages": {

  "javascript""html"

  },

分类:

前端

标签:

Vue.js

作者介绍

Shinkai005
V1

公众号:深海笔记Shinkai