VUE学习随笔

VUE

做的事儿和二阶段一样,但是语法变化较大,一切的框架都是为了简化DOM操作(语法麻烦、渲染多了影响效率)

 

 

 

一、vue介绍

渐进式JavaScript框架,易学易用,性能出色,适用场景丰富的 Web 前端框架。(难度还好,但是量大) 构建数据驱动的web应用开发框架,属于前端框架。

  • 为什么受欢迎? 1、声明式渲染:应对前端后分离开发的大趋势 2、渐进式框架:适应各种业务需求以及场景(vue从小到大都可以胜任) 3、更适合移动端:现在的趋势也是移动端为主,SPA页面(单页面开发 - 效率更高,只有一个.html文件) 4、快速交付:结合一些第三方UI插件库/框架/组件库 - elementUI(PC端)/vantUI(移动端) 5、企业需求:必备技能(vue或react 二选一) 6、中国的框架(作者借鉴了react和angular)

  • vue是一个属于mvvm架构的框架,什么是mvvm? m - model:模型数据 v - view:视图 vm - ViewModel:vm控制器 我们一般统称为mv*架构:mvc、mvp、mvvp

  • 学习目的:vue一共学习4周,呆老师教你一周vue基础,vue全家桶由三部分组成: 1、vue 2、vue router - vue路由,做项目的时候才学习 3、vuex - 状态机:在不同的页面,我们需要一个状态,来判断什么操作,比如登录了吗,类似于我们二阶段学习的webStorage

  • 开发环境搭建: 1、下载引入vue.js(版本2.0和3.0,我们都学习):<script src="2.0或3.0"></script> 2、脚手架方式 - 项目开发时才用,深入学习后

 

二、vue的使用模板

1、vue2.0的模板和class和style操作样式 :

  • 模板

顺序无所谓,但是一定要按照这些键值对来玩

         new Vue({
  el:"#box",//vue确定使用范围,只能在id叫box的元素里,才可以使用vue的语法,控制环境范围
  data:{//模型数据:vue专门为你提供了放变量的地方
  变量名:值,
  ...
  },
  methods:{//事件方法:vue专门为你提供了放事件的地方
  函数名(){
  功能
  },
  ...
  },
  })
  • vue2的class和style操作样式 - vue.js在控制样式:

 1、class操作样式:- 两种语法糖
  <elem :class="obj"></elem> - 对象口味的语法糖,对应下方的模型数据,可知class最终只有aa和bb
  <elem :class="arr"></elem> - 数组口味的语法糖,对应下方的模型数据,可知class最终只有aa和bb
 
  new Vue({
  el:"#box",
  data:{
  obj:{ - 对象口味的语法糖
  aa:true,
  bb:true,
  cc:false,
  ...
  }, - 后续不能直接添加dd,vue底层具有拦截机制,想要添加,必须vue提供的方法:Vue.set(Vm对象.obj,"dd",true)
  arr:["aa","bb",...] - 可以随时的添加和删除,相比对象口味语法糖更加的随意简单
  },
  })
 
 2、style内联操作样式:
  <elem :style="obj"></elem> - 对象口味的语法糖,对应下方的模型数据,可知现在具有背景颜色为红色
  <elem :style="arr"></elem> - 对象口味的语法糖,对应下方的模型数据,可知现在具有背景颜色为红色
 
  new Vue({
  el:"#box",
  data:{
  obj:{ - 对象口味的语法糖
  backgroundColor:"red",
  ...
  }, - 后续不能直接添加样式,vue底层具有拦截机制,想要添加,必须vue提供的方法:Vue.set(Vm对象.obj,"样式名","样式值")
  arr:[{"backgroundColor":"red"},...]
  },
  })

 

 

2、vue3的模板以及class和style的样式操作:

注意:Vue3除了语法不同,生命周期中的两个销毁也不一样:beforeUnmount、unmounted

     1、模板:vue是不需要实例化对象的(不需要new XXX)
  直接写为:
  var app=Vue.createApp({
  //创建变量有所不同,写为函数式创建
  data(){
  return {
  name:"paoge"
  }
  },
  methods:{},
  computed:{},
  watch:{},
  .....
  }).mount("#box");//mount - 挂载
 
  app.component("组件名",{   //组件写法与vue2不同
  template:``,
  })
 
  2、反而vue3操作样式不用担心vue2的问题,之前vue2的对象语法糖的拦截部分,可以忽略不管了额,对象可以直接使用老JS语句添加/删除了

 

 

 

三、vue2,3公共用法

1、vue插值表达式:

  • {{变量}} - 在HTML上实现了一个基本的js环境,可以进行js运算、放入变量、三目、甚至API都可以在HTML上书写

2、vue指令:

  • 写在HTML上的v-xxx的特殊属性,就是所谓的指令

 vue指令:写在HTML上的v-xxx的特殊属性,就是所谓的指令
  v-html - 类似于innerHTML,可以识别渲染标签
  语法:<elem v-html="变量"></elem> - 此标签中就会具有变量的值/内容
  特殊:不要使用插值表达式渲染页面,插值表达式类似的是innerText不识别标签的,当作原文处理
 
  v-for - 类似for in循环,数据渲染!
  语法:<elem v-for="(v,i) in 数组名"></elem> - 会根据数组中的元素渲染出多个此元素elem,可以拥有值和下标(由你自己决定)
 
  v-model - 具有双向数据绑定功能,页面控制变量,变量也能控制页面
  语法:<input v-model="变量"> - input的默认值就为变量的值,并且input修改内容,变量也会跟着一起变化(以后可以不用oninput/onblur事件就可以得到用输入的value)
 
  v-show - 隐藏和显示,传入的是一个布尔值,底层原理:display:block/none;
  v-if - 是否渲染,,传入的是一个布尔值,底层原理:appendChild/remove;
  语法:<elem v-show/if="布尔变量"></elem>//如果布尔值为true则显示,如果为false则隐藏
 
  v-bind:属性名="变量" - 意味着原来JS标准属性里面是不可以放入变量的,但是现在可以了,简写方式 - :class="变量"
 
  v-on:事件名="函数名()" - 绑定事件的,简写方式 - @事件名="函数名()";

 

1.条件渲染v-if、v-else-if、v-else:

 1、订单显示:
  <ul>
  <li v-for="obj in datalist" :key=obj.id>
  {{obj.title}}---
  <span v-if="obj.state===1">未付款</span>
  <span v-else-if="obj.state===2">待发货</span>
  <span v-else-if="obj.state===3">已发货</span>
  <span v-else>已签收</span>
  </li>
  </ul>
    通过以上代码,我们可以实现:
  1、根据datalist数据渲染出很多个li
  2、并且判断datalist里面每个对象的状态,显示出不同的span或不同的文字
  并不只有v-if,还有v-else-if、v-else,可以让我们在多个条件中选择其中一个 (隐藏和显示)
 
 2、如果希望多个子元素同时显示|同时隐藏,可以在父元素上设置一个v-if,但是推荐使用template标签,这是一个vue提供的包装元素,并不会真的渲染到DOM树上,不会创建在页面上的
  也是我们见过的第一个虚拟DOM节点:<template></template>

 

2.列表渲染v-for:

 1、v-for:可以遍历数组、对象、甚至是一个数字
  <ul>
  <li v-for="(v,i) in 需要被遍历的数据" :key="不重复的东西">{{v}}</li> - 注意:遍历数字基本没什么意义,不管是遍历对象还是数组,前面始终是值,后面始终是下标
  </ul>
 
 2、面试题:为什么v-for过后都要添加一个自定义属性key?
  以前二阶段:数据->渲染到DOM数据,(不管是渲染还是删除,只要DOM变化)渲染次数越多,性能就越差
  虚拟DOM:数据->vue变为虚拟DOM:js对象描述了一个节点->真实DOM
  新的数组会生成新的虚拟DOM,然后vue底层会使用diff算法拿着新生成的虚拟DOM和老的真实DOM进行对比,找不同
  找到不同后,会更新出一个补丁,再渲染到真实DOM之中,这样的好处就是性能代价最小
  为什么说虚拟DOM代价小呢?因为真实DOM非常的复杂,有很多很多的属性,但是虚拟DOM只需要重要的属性
 
  虚拟DOM中用到的diff算法默认也是比较笨的,会一一的进行对比,效率低下,所以建议添加key属性
  理想情况:key="v.id",id是绝对不会重复的
 
  强调/记死:
  1、只要用了v-for就要用上:key,为了触发虚拟DOM
  2、:key必须写一个不重复的东西,千万别是下标,最好是ID
  目的:高效复用DOM
 
 3、数组更新检测:
  1、不能监测数组变动的操作
  arr[下标]=新值;
  vue3不必担心此问题了
 
  2、强烈推荐:都可以监测到数组变动,页面也就会跟着变化
  push/pop/shift/unshift/splice/sort/reverse
 
  3、一般般的:
  filter/concat/slice/map - 不会修改原数组,只返回新数组,新数组又不会影响到页面,那我们必须用新数组去覆盖原数组才可以改到页面(数据驱动视图)

3.事件处理器:

 1、*绑定事件:@事件名="函数名()";
      *特殊:
  1、函数名的(),如果不传入参数,其实可以省略不写
  2、如果调用时,没有加(),我们的methods事件函数甚至会自动获得一个形参 - event对象
  3、如果调用时,传入了自己的实参,但又想得到event对象,必须固定写为:
  <button @click="f1($event,1,2,3)">按钮</button>
 
  2、事件修饰符:
  @事件名.stop="函数名()"; - 阻止冒泡
  @事件名.self="函数名()"; - 只有点击自己才触发
  @事件名.prevent=函数名()"; - 阻止默认行为
  都是在简化event的事情
 
  3、按键修饰符:
  @keydown.enter="函数名()" - 只有回车才会触发
  @keydown.enter.ctrl="函数名()" - 只有回车和ctrl同时使用才会触发
  还有很多:.esc .up .left .right .down .space   .shift   .delete 甚至可以.键码
 

 

4.表单控件:

(写在form元素里面的标签就是表单控件)绑定:v-model - 记住:以后有没有事件我们都可以得到用户输入/选择的东西 - 【双向数据绑定】

 1、获取input中用户输入的内容
  <input type="text" v-model="变量" /> - 只要用户输入了,变量就会自动变化,自动得到
 2、多选框:想要知道被选中没有 (购物车全选)
  <input type="checkbox" v-model="布尔变量" />
  如果用户操作了页面这个多选框,那么此布尔值就会自动变化,如果用户勾选了,则为true,如果用户没选上,则为false
 
 3、如果有多个多选框:想要知道谁被选中了
  <input type="checkbox" v-model="arr" value="苹果" />苹果
  <input type="checkbox" v-model="arr" value="香蕉" />香蕉
  <input type="checkbox" v-model="arr" value="梨子" />梨子
  注意:必须用数组变量,保存input的value值,此数组中有哪些人的value,哪些人就会被勾选中,反之没有
 
 4、单选框:判断选中了谁
  <input type="radio" v-model="gender" value="男" />男
  <input type="radio" v-model="gender" value="女" />女
 
  根据gender变量中保存的value值,来判断你选中的是谁
 
 强调:单选框和多选框不要用点击事件,时机不对,必须使用change事件
 
 5、表单修饰符:
  v-model.lazy="变量"; - lazy懒惰,只会在失去焦点时获取到用户输入的内容
  v-model.number="变量"; - 自带隐式转换为数字的操作(以前我们说页面上一切用户输入的数据都是字符串)
  v-model.trim="变量"; - 去掉字符串开头结尾的空白字符

 

5.自定义指令:

为了操作底层dom,作者给我们留的方案,你觉得他提供的指令不够玩了,我们可以自定义指令(自己书写底层javascript原理)

 何时:我想要操作dom,作者还没提供
  创建指令:
  Vue.directive("paoge",{
  //指令的生命周期
  inserted(el,binding){//第一次会使用指令时会执行
 // console.log(el);//当前使用了此指令的元素
 // console.log(binding);//对象,binding.value 就可以得到用户传给我们的数据
  el.style.background=binding.value
  },
  update(el,binding){//指令修改后,想要再次执行,需要 写update生命周期
  el.style.background=binding.value
  }
  })
 
 简化:简化后不光具有inserted的功能也具有update的功能
  Vue.directive("paoge",()=>{
  el.style.background=binding.value
  })
 
 
 注意:
  1、vue3的指令的生命周期和vue2并不一样,约等于 组件的生命周期
  2、this.$nextTick(()=>{
  比生命周期updated执行的还要晚,在此处更适合调用插件初始化(new Swiper)操作
      })

 

 

 

3、计算属性:

防止模板过重,【难以维护】,负责逻辑计算的操作全部放到计算属性之中来写

 var vm=new Vue({
  data:{},//状态、变量、模型数据
  methods:{},//方法 - 事件
  computed:{//方法 - 计算
  函数名(){
  return 结果;
  特殊:
  1、在HTML使用时,函数名不需要();
  2、必须添加return进行返回结果
  3、和methods很像,但是methods调用了几次就会执行几次,但是computed如果数据不方法变化,他只会做第一次
  }
  }
  })

 

 

4、监听属性:

 var vm=new Vue({
  data:{},//状态、变量、模型数据
  methods:{},//方法 - 事件
  computed:{},//方法 - 计算
  watch:{//方法 - 专为监听input准备的
  v-mdel绑定的变量名(newval,oldval){//能够时刻监听到数据的变化,比如:input不再需要绑定oninput和onblur事件
  操作
  }
  }
  })
 
 总结:
  1、data -> 状态、变量、模型数据
  2、methods:事件
  3、computed:重视结果,逻辑计算。解决模板过重的问题(以后方便维护),只求结果,必须要有return
  4、watch:监听一个值的改变
 
 Vue2也叫做选项式API - 你想要哪部分,需要自己选择
 Vue3也叫做组合式API

 

 

 

 

 

 

 

四、组件化开发

为什么要组件化: 1、扩展HTML元素,封装可以重用的代码 2、单页面开发,其实就是在调用各种各样的组件

1、组件的创建/注册:

     1、全局组件/局部组件:
  Vue.component("组件名",{   //component组成部分
  template:`<div css/js>内容</div>`, - 写HTML模板   //template模板
  methods:{}, //方法-用于事件
  computed:{}, //计算
  watch:{}, //监视
  data(){
  return {
 
  }
  },
  components:{//局部组件
  "组件名":{
  template:`<div css/js>内容</div>`,
  ...套娃
  }
  }
  })
  new Vue({}) 根组件
 
 
 
  2、使用组件:<组件名></组件名>
 
  3、注意:
  1、起名字:如果js写为驼峰命名,HTML不支持,必须写为连接符-
  2、dom片段(template模板),没有代码提示,没有高亮显示 - 下周vue单文件组件才可以解决
  3、css只能写成行内样式 - 下周vue单文件组件才可以解决
  4、template只能包含一个根节点
  5、自定义组件的data都必须是vue3的函数式写法
  6、所有的组件都放在一个.js里肯定太乱了, - 下周vue单文件组件才可以解决
  7、组件是一座孤岛,无法【直接】访问外面你的组件的状态或方法 - 明天学习的【组件通信交流】
 
 何时使用全局或局部组件:
  1、如果一个组件只会使用过一次推荐定义为局部
  2、如果一个组件在不同的页面、在不同的各个组件中都会使用到,推荐为全局

 

 

 

2、组件通信 :

组件是一座孤岛,默认无法状态(data)通信,父子关系极差

目的 - 提升组件的复用性

比如:一个网站上的任何一个页面,都有导航条,相似却不相同,我们可以实现一个组件,传入不同的参数实现不同的效果

 

1.父传子:

     自定义属性
  <组件名 自定义属性名="根组件的data数据"></组件名>
 
  Vue.component("组件名",{
  template:``,
  props:["自定义属性名"],
  props:{
  自定义属性名:{
  type:String,
  default:默认值,
  }
  }
  })
 --------------------------------------------------
 详细例子:
 //在根组件中的#box里面将自定义属性的值传给全局组件,子组件用props存储。
    //props的第一种写法的html
  <div id="box">
  <navbar myname="首页" :bool="false" :bool1="true"></navbar>
  <navbar myname="购物车页" :bool="true" :bool1="true"></navbar>
  <navbar myname="产品页" :bool="true" :bool1="false"></navbar>
  </div>
  //props的第二种写法的html
  <div id="box">  
  <navbar myname="首页" :bool="false"></navbar>
  <navbar myname="购物车页"></navbar>
  <navbar myname="产品页" :bool1="false"></navbar>
  </div>
 
  <script src="./js/vue.js"></script>
  <script>
  //全局组件
  Vue.component("navbar", {
  template: `
  <div>
  <button v-if="bool"><</button>
  <span>{{myname}}</span>
  <button button v-if="bool1">三</button>
  </div>
  `,
  data() {
  return {
 
  }
  },
  //props的第一种写法::数组语法糖,接收到根组件上传入的自定义属性,我就可以在自己的DOM模板上使用此属性/变量
  // props:["myname","bool","bool1"],
 
  //props的第二种写法:对象语法糖,可以限制数据类型&默认值
  props: {
  myname: {
  type: String, //规定了数据类型
  default: "导航条" //设置默认值
  },
  bool: {
  type: Boolean,
  default: true
  },
  bool1: {
  type: Boolean,
  default: true
  }
  }
  })
 
  //根组件
  new Vue({
  el: "#box",
  data: {
  }
  })
  </script>
 

 

2.子传父:

实现一个抽屉侧边栏效果,把按钮封装为组建后,按钮点击事件无法操作根组件中的状态data,所以需要用到子传父通信

     1、子组件:
  this.$emit("自定义事件名",想要传的数据);
 
  2、<div id="box">
  <子组件 @自定义事件名='父函数'></子组件>
    </div>
 
  3、父组件:
  methods:{
  父函数(data){
  data->得到子传给我们的数据
  }
  }
 
  更详细,见案例
 

 

3.中间人模式:

 总结:
  父传子 - 用属性(自定义属性&props)
    子传父 - 用事件(自定时间是&this.$emit)
 
  子->父->另一个子
 

 

 

4.bus总线:

bus:中央事件总线,实现较为复杂的通信

 1、创建bus:var bus=new Vue();
 
 2、传/收数据:
  1、订阅者: - 多半需要搭配上生命周期mounted
  bus.$on("自定义名称/通行令名称",(data)=>{  
  data->得到发布者传输过来的数据
  })
 
  2、发布者:
  bus.$emit("自定义名称/通行令名称",传输的数据)

 

以上的通信,都是需要一个愿意给,一个愿意拿。以后更棒的是vuex状态

 

5.refs:

父组件可以随意的玩弄子组件(获取/修改)- 面试中

 语法:比如我现在有两个组件,分别都打了个标记ref="自定义名"
  <div id="box">
  <child1 ref="自定义名1"></child1>
  <child2 ref="自定义名2"></child2>
  </div>
 
 根组件:
  this.$refs -> 得到所有具有ref属性的子组件
  this.$refs.自定义名 ->得到我想要操作的某个组件
  this.$refs.自定义名.变量名 ->得到我想要操作的某个组件的变量
 
 注意:
  1、ref和$refs是固定关键字,不能修改
  2、打破了传统的通信流程,比如我们想要获取一个input的value值,在vue中可以用v-model,但是react中没有,则可用ref完成!
  3、如果组件中写了一个指令v-once,一次性,状态改变,页面上的组件也不会变化,只有打开页面第一次渲染会成功

6.内置组件:

  1. <template ></template > 不会显示在html中,可以用来操作多个元素

  2. <component :is="组件名"></component> - 告诉他现在该显示哪个组件

  3. <keep-alive></keep-alive>- 活着,就算选项卡切换了,回来你输入的东西依然存在,往往和上一个内置组件component搭配使用

  4. <slot></slot> :插槽,【组件标签中,使用时默认是不允许在嵌套其他标签的】,所以提供了slot扩展组件的能力,提高组件的复用性

                 <carousel>
      <img src="1.jpg"/>
      <img src="2.jpg"/>
      <img slot="a" src="3.jpg"/> //具名插槽对应写法
     
      <template v-slot:a> //具名插槽的第二种写法,不常用
      <img src="./img/3.jpg">
      </template>
      </carousel>
     
     
      Vue.component("carousel",{
      template:`
      <div>
      <slot></slot>//单个插槽:保存住了1和2图片
      轮播
      <slot name="a"></slot>//具名插槽:保存住3图片
      </div>
      `
      })

     

  5. 过渡:添加动画

             <style type="text/css">
      body,html{
      width:100%;
      overflow: hidden;
      }
      .paoge-enter-active{
      animation: aaa 1.5s;
      }
     
      .paoge-leave-active{
      animation: aaa 1.5s reverse;
      }
     
      @keyframes aaa{
      from{
      opacity: 0;
      transform: translateX(100px);
      }
      to{
      opacity: 1;
      transform: translateX(0px);
      }
      }
      </style>
     
      <div id="box">
      <transition enter-active-class="进入动画的class" leave-active-class="离开的动画的class">
      <div v-if="bool">11111111111</div>
      </transition>
      </div>
     
      可以简写:
      <transition name="paoge">
      <div v-if="bool">11111111111</div>
      </transition>
     
     
     
     
      补充:1、如果希望一打开页面就有一次动画,可以在transition上面加一个appear属性
      2、如果多个元素希望过渡,就别用,v-show,用v-if、v-else
      <transition name="paoge" mode="out-in" appear>
      <div v-if="bool" key="1">11111111111</div>
      <div v-else key="2">22222222222</div>
      </transition>
      //注意:key必须写,且key值不相同
     
      3、多个组件实现过渡:依然同上:
      <transition name="paoge" mode="out-in">
      <keep-alive>
      <component :is="yemian"></component>
      </keep-alive>
      </transition>
     
      4、多个列表实现过度:(transition-group一般只用于列表)
      <transition-group name="paoge" tag="ul">
      <li v-for="(v,i) in arr" :key="v">{{v}} -
      <button @click="del(i)">x</button>
      </li>
      </transition-group>
      //tage属性:可以自定义标签,如果不写默认为sapn

     

7.组件的生命周期:

一共4组8个,再不同的时间/时刻如果写了这个【生命周期函数】就会自动触发,如果没写则不执行,可以让我们再某个时刻干某些事

 new Vue({
  data:{},
  methods:{},
  computed:{},
  watch:{},
  1、beforeCreate(){//创建之前:在这个时刻,我们连状态都获取不到,没用
  console.log("我是beforeCreate",this.name);
  },
  2、created(){//*创建之前,初始化状态或挂载到当前示例的一些属性,【可以发起ajax】,但是有一个人更优秀
  console.log("我是created",this.name,this.$el);
  },
  3、beforeMount(){//挂载之前,提供了你模板解析之前最后一此修改模板节点的机会 - 没用
  console.log("我是beforeMoun",this.$el,document.getElementById("box").innerHTML)
  },
  4、mounted(){//***挂载之后,拿到真实的dom节点 - 依赖于dom创建之后,才能进行初始化工作的插件(可以发起ajax&调用一些插件操作)
  console.log("我是mounted",document.getElementById("box").innerHTML)
  },
  5、beforeUpdate(){//更新之前,记录着老的dom的某些状态,比如滚动条位置... 没用,记录着的是之前的东西,和页面完全没对应上
  console.log("我是beforeUpdate,只有在更新数据的时候会自动执行",document.getElementById("box").innerHTML)
  },
  6、updated(){//*更新之后,更新数据完了,你要做别的什么操作用此钩子函数
  console.log("我是updated,只有在更新数据的时候会自动执行",document.getElementById("box").innerHTML)
  }
  7、beforeDestory(){
  console.log("我是销毁后,清除定时器");
  },
  8、destroyed(){
  console.log("我是销毁后,清除定时器");
  }
  })
 
  面试中,不管别人问你vue的生命周期,组件的生命周期,组件的钩子函数,组件的生命周期钩子,都是再问你同一个问题:
  4组8个,分别是哪8个,这个8个分别在什么时候执行

 

  • Swiper轮播插件 变成一个 组件

  •  

 

 

posted on   Elementinner  阅读(53)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示