vue2-2024(1)(超全基础+难点)

 Object.defineProperty数据代理 &Observer数据劫持

数据代理,通过一个对象代理对另一个对象中属性的操作(读/写)

数据代理+数据劫持 ?  数据的双向绑定(vue中)

Vue 利用 Object.defineProperty 创建一个 observer 来劫持监听所有的属性,把这些属性全部转为 getter 和 setter。
Vue 中每个组件实例都会对应一个 watcher 实例,它会在组件渲染的过程中把使用过的数据属性通过 getter 收集为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

修改data属性值-》重新解析模板-》生成新的(虚拟)dom-》diff算法对比-》生成更新后页面

 let number=10
  let person={
    name:"lisi",
    sex:"男",
    age:number,
  }
  Object.defineProperty(person,"age",{
    // value:19,
    // enumerable:true,//可枚举
    // writable:true //可修改
    get(){
      debugger
      return  number
    },
    set(value){//value为 person.age=1   中的1
      debugger
      number=value
    }
  })
  person.age=1
  // for in  即可遍历数组也可遍历对象
  // for (const key in person) {
  //   if (Object.hasOwnProperty.call(person, key)) {
  //     const element = person[key];
  //     console.log(element)
  //   }
  // }
  

  console.log( Object.keys(person))
  let obj1={
    "x":12
  }
  let obj2={
    name:"lisi",

  }
  Object.defineProperty(obj2,"x",{
    set(value){
      obj1.x=value
    },
    get(){
      return obj1.x
    }
  })

添加class样式

字符串写法

<template>
  <div class="hello" :class="a" @click="changeColor()">
   {{msg}}
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      a:"red"
    }
  },
  methods:{
    changeColor(){
      this.a="green"
    }
  }
}
</script>

数组写法

 <div class="hello" :class="classarr" @click="changeColor()">


data(){
    return{
      classarr:["red","green","orange"]
    }
  },

对象写法 

  <div class="hello" :class="classobj" @click="changeColor()">
 

data(){
    return{
      classobj:{
        "red":true,
        "green":false,
        "orange":false,
      },
    }
  },

绑定style样式

方式1

<template>
  <div class="hello" :style="styleobj"  @click="changeColor()">
   {{msg}}
  </div>
</template>

data(){
    return{
     
      styleobj:{
        fontSize:"40px"
      }
    }
  },

方式2 

  <div class="hello" :style="{fontSize:fontsize}"  @click="changeColor()">

方式3

:style[a,b]

a和b为样式对象 如:

styleobj:{
        fontSize:"40px"
      }

v-if

<div v-if="n===1">1</div>
<div v-else-if="n===2">1</div>
<div v-else-if="n===3">1</div>
<div v-else>1</div>

计算属性

计算属性回调函数

2个时刻调用:初始化和方法里面的数据改动

<template>
  <div class="hello" >
   <input type="text" v-model="inputtext">
   <button @click="sortAge=1">年龄升序</button>
   <button @click="sortAge=2">年龄降序</button>
   <button  @click="sortAge=0">原顺序</button>
   <ul >
    <li v-for="item in filperson" :key="item.id">
      {{ item.name }}  ------  {{ item.age }}
    </li>
   </ul>
  </div>
</template>

<script>

/* eslint-disable */
import { watch } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      sortAge:0,//1升序,2降序,0原顺序
      arr:[
        {"id":"1","name":"lisi1","age":12},
        {"id":"2","name":"lisi2","age":11},
        {"id":"3","name":"wangwu1","age":33},
        {"id":"4","name":"wang2","age":55}
      ],
      endarr:[],
      inputtext:""
    }
  },
  methods:{
  },
  computed:{
    // 默认执行一次,this.inputtext发生变化则计算一次
     
    filperson(){
        let starr= this.arr.filter((item)=>{
          return  item.name.includes(this.inputtext)
        })
        
        if(this.sortAge){
          debugger
          starr.sort((a,b)=>{
            return this.sortAge==1?a.age-b.age   :b.age-a.age
          })  
        }
      return starr
      }
  },
  
}
</script>

条件过滤


<template>
  <div class="hello" >
   <input type="text" v-model="inputtext">
   <ul>
    <li v-for="item in endarr" :key="item.id">
      {{ item.name }}
    </li>
   </ul>
  </div>
</template>

<script>

/* eslint-disable */
import { watch } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      arr:[
        {"id":"1","name":"lisi1"},
        {"id":"2","name":"lisi2"},
        {"id":"2","name":"wangwu1"},
        {"id":"3","name":"wang2"}
      ],
      endarr:"",
      inputtext:""
    }
  },
  methods:{
  },
  watch:{
     // 简写形式
    // inputtext(newvalue){
    //  this.endarr= this.arr.filter((item)=>{
    //     return  item.name.includes(newvalue)
    //   })
    // }
    // 完整形式
    inputtext:{
      // 初始化的时候立即执行
      immediate:true,
      handler(newvalue){
        this.endarr= this.arr.filter((item)=>{
          return  item.name.includes(newvalue)
        })
      }
    }
  }
}
</script>

后期给对象添加属性

<template>
  <div class="hello" >
   
    <p>姓名:{{person.name}}</p> 
    <p>姓名:{{person.age}}</p> 
    <button @click="updata"> person添加属性</button>
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';
// import Vue from 'vue/types/umd';
// import { person } from '../../../hellovue3/src/types/index';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      person:{
        "name":"lisu",
      }
      
    }
  },
  methods:{
    updata(){
     // 方法1
      // Vue.set(this.person,"age","boo")//只可给data里面的对象上添加属性,不可给data添加
      // 方法2
      this.$set(this.person,"age","boo")
    }
  },
}
</script>

收集表单里面的信息

<template>
  <div class="hello" >
    <!-- prevent组织默认刷新行为 -->
    <form @submit.prevent="sub">
   账号:<input type="text" v-model.trim="person.acount"><br/><br/>
   密码:<input type="password" v-model="person.password"><br/><br/>
   年龄:<input type="number" v-model.number="person.age"><br/><br/>
   性别:<label for="nan">男</label> <input v-model="person.personSex" type="radio" name="sex" id="nan" value="male">
         <label for="nv">女</label> <input v-model="person.personSex" type="radio" name="sex"  id="nv" value="famale"><br/><br/>
   爱好:学习<input type="checkbox" v-model="person.like" value="lea">
         打游戏<input type="checkbox" v-model="person.like" value="dyx">
         吃美食<input type="checkbox" v-model="person.like" value="cms"><br/><br/>
  喜欢城市:<select name="" v-model="person.city" aria-placeholder="请选择喜欢的城市" id="">
              <option value="1">上海</option>
              <option value="2">北京</option>
              <option value="3">深圳</option>
              <option value="4">广州</option>
            </select><br/><br/>
            <!-- v-model.lazy失去焦点更新数据 -->
  其他信息:<textarea name="" v-model.lazy="person.other" id="" cols="30" rows="10">

            </textarea><br/><br/>
            <!--checkbox不设置value值   则是否打勾为true或者false  -->
            <input type="checkbox" v-model="person.agree">我同意<br/><br/>
            <button>提交</button>
          </form>
  </div>
</template>

<script>


import Vue, { watch } from 'vue';

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      person:{

        acount:"",
        password:"",
        like:[],
        personSex:"",
        city:"",
        age:0,
        other:"",
        agree:''
      },
    }
  },
  methods:{
    sub(){
      console.log("提交")
      console.log(JSON.stringify(this.person))
    }
  },
}
</script>

v-html指令安全问题

cookie中 k1  ,k2的值被篡改,则不安全;

被其他网站获取到也不安全,获取到可直接登录(httponly可避免通过代码获取cookie)

 

指令

v-clock

指令+样式  当网络延迟时,动态渲染的页面字段不显示,当页面渲染结束后,vue自动删除v-clock


<template>
  <div class="hello" >
  <p v-cloak>{{name}}</p>
  <p v-cloak>{{age}}</p>
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      name:"1111",
      age:"2"
    }
  },
  methods:{
    
  },
}
</script>
<style scoped>
[v-cloak]{
  display: none;
}
.hello{
  width: 100%;
  height: 100px;
  /* border: 1px solid #dedede; */
  text-align: left;
}
</style>


v-pre   
跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。


v-once 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。
 

自定义指令

自定义指令的两种实现方式


<template>
  <div class="hello" >
    <!-- 指令v-big,num放大10倍 -->
    <!-- v-focus  页面刷新时得到焦点 -->
  <p >{{num}}</p>
  <!-- 放大10倍后的n -->
  <p v-big="num"></p>
  <button @click="num++">num加一</button><br/>
  <input v-focus="num" type="text"><br/>
  <input v-big-number="num"  type="text">
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';

// 全局自定义指令两种方法
// Vue.directive("big",function (element,binding){
//       element.innerText=binding.value*10
//     })
// Vue.directive("focus",{
//       // 指令和元素成功绑定时(一上来,并不是放入页面时)
//       bind(element,binding){
//         element.value=binding.value
//       },
//       // 指令所在元素被插入页面时
//       inserted(element,binding){
//         element.focus()
//       },
//       // 指令所在的模板被从新解析时
//       update(element,binding){
//         element.value=binding.value
//       }
//     })
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      num:1,
    }
  },
  methods:{
    
  },
  directives:{
    // big函数何时会被调用?
    // 1.指令和元素成功绑定时(一上来,并不是放入页面时)
    // 2.指令所在的模板被从新解析时
    big(element,binding){
      
      element.innerText=binding.value*10
    },
    focus:{
      // 指令和元素成功绑定时(一上来,并不是放入页面时)
      bind(element,binding){
        element.value=binding.value
      },
      // 指令所在元素被插入页面时
      inserted(element,binding){
        element.focus()
      },
      // 指令所在的模板被从新解析时
      update(element,binding){
        element.value=binding.value
      }
    },
    'big-number'(element,binding){
      console.log(element,binding.value)
      element.value=binding.value*10
    } 
   }
}
</script>
<style scoped>
[v-cloak]{
  display: none;
}
.hello{
  width: 100%;
  height: 100px;
  /* border: 1px solid #dedede; */
  text-align: left;
}
</style>

一个重要的内置关系

function Person(){
      this.name="lisi",
      this.age=10
    }
let p=new Person()
Person.prototype===p.__proto__ //显示原型属性和隐式原型属性   true

VueComponent.prototype.__proto__=Vue.prototype

为什么 要有这个方法?让组件实例对象(vc)可以访问到vue原型上的属性/方法

 ref和props的使用

ref给节点打标识

1.放在节点上可获取html节点 //<div>1</div>

2.放在组件上可获取子组件中定义的值

//父
<template>
  <div id="app">
    <div v-text="numapp" ref="div"></div>
    <HelloWorld ref="vc" msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  },
  data(){
    return{
      numapp:1
    }
  },
  mounted(){
    console.log(this.$refs.div);
    console.log(this.$refs.vc.num);//num为子组件定义变量
  }
}
</script>

//子
<template>
  <div class="hello" >
   <div>{{ msg }}</div>
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      num:1,
    }
  },
  methods:{
    
  },
}
</script>

props(父传子)的两种写法:

props不可改指的是修改对象的整个地址,可修改对象里面某个属性值和基本数据类型(不建议)

1. props:["msg","age","name"]

2.

props:{

 msg:{

     type: String,

     required:true,

     default:"222"//一般不和 required一起定义

    }

}

mixin混入

可以把多个组件公用的配置提取成一个混入对象

1,局部;2,全局

//mixins.js
export let hunru={
  methods:{
    tc(){
      alert(this.msg)
    }
  },
  
}
export let init={
  mounted(){
    console.log("init....");
  }
}

//组件1
<template>
  <div class="hello" >
    <p @click="tc">person</p>
   <div>{{ msg }}</div>
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';
import {hunru,init} from '../mixins'
export default {
  name: 'HelloWorld',
  props: {
    msg:{
     type: String,
     required:true,
     default:"222"
    } 
  },
  data(){
    return{
      num:1,
    }
  },
  mixins:[hunru,init],
  // mounted(){
  //   console.log("init....");
  // }
  // methods:{
  //   tc(){
  //     alert(this.msg)
  //   }
  // },
}
</script>
//组件2

<template>
  <div class="hello" >
    <p @click="tc">HelloWorld</p>
   <div>{{ msg }}</div>
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';
import {hunru} from '../mixins'
export default {
  name: 'HelloWorld',
  props: {
    msg:{
     type: String,
     required:true,
     default:"222"
    } 
  },
  data(){
    return{
      num:1,
    }
  },
  mixins:[hunru],
  methods:{
    
  },
}
</script>

全局 

引入插件

插件
功能:用于增强Vue
本质:包含安装方法的一个对象,安装程序的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
定义插件:
对象。安装=函数(选项){
//1.添加全局过滤器
Vue.filter(....)
// 2.添加全局指令
Vue.directive(....)
//3.配置全局混入(合)
Vue.mixin (....)
//4.添加实例方法
Vue.prototype.$myMethod =function () {...}
Vue.prototype.$myProperty=xxxX
}
使用插件:Vue.use()

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import plugins from'./plugins'
//关闭Vue的生产提示
Vue.config.productionTip = false
//应用(使用)插件
Vue.use(plugins)
Vue.use(plugins)//其他插件
Vue.use(plugins)//其他插件
Vue.use(plugins)//其他插件
//创建vm
I
new Vue({
el:'#app',
render: h => h(App)
})

安装less-loade

npm i less-loader

//   "less-loader": "^8.0.0",  webpack为5.0.0以及以上才可兼容

 组件化编程todos小demo

1.组件化编码流程:
(1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一
些组件在用:
1).一个组件在用:放在组件自身即可。
2).一些组件在用:放在他们共同的父组件上(状态提升)。
(3).实现交互:从绑定事件开始。
2. props适用于:
(1).父组件==>子组件 通信
(2).子组件==>父组件通信(要求父先给子一个函数)
3.使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props
是不可以修改的!
4. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推
荐这样做。

 app.vue

<template>
  <div id="app">
    <MyHeader ref="headerText"  :getobj="getobj"/>
    <MyList text="text" :deleteList="deleteList" :list="list" :checktodo="checktodo"/>
    <MyFooter :list="list" :checkAllList="checkAllList"/>
  </div>
</template>

<script>
/* eslint-disable */
import MyHeader from './components/todos/MyHeader.vue'
import MyFooter from './components/todos/MyFooter.vue'
import MyList from './components/todos/MyList.vue'

export default {
  name: 'App',
  components: {
    MyHeader,
    MyFooter,
    MyList
  },
  data(){
    return{
      "text":"",
      list:JSON.parse(localStorage.getItem("list"))||[],
    }
    
  },
  mounted(){
   this.$bus.$on("checktodo",this.checktodo)
   this.$bus.$on("deleteList",this.deleteList)
   this.$bus.$on("updateList",this.updateList)
  },
  beforeDestroy(){
    this.$off(['checktodo','deleteList','updateList'])
  },
  methods:{
    //修改 
    updateList(id,title){
      for (let index = 0; index < this.list.length; index++) {
        
        if(this.list[index].id==id){
          this.list[index].title=title
        }
      }
    },
    // 添加
    getobj(obj){
      this.list.unshift(obj)
    },
    // 勾选
    checktodo(id){
      for (let index = 0; index < this.list.length; index++) {
        if(this.list[index].id==id){
          this.list[index].done=!this.list[index].done
        }
      }
    },
    // 删除
    deleteList(id){
      console.log(id)
      this.list=this.list.filter((item)=>{
        return item.id!==id
      })
      console.log( this.list)
    },
    // 全选或者全部选
    checkAllList(status){
      for (let index = 0; index < this.list.length; index++) {
        this.list[index].done=status
      }
    }
  },
  watch:{
    list:{
      deep:true,
      handler(value){
        localStorage.setItem("list",JSON.stringify(value))
      }
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
}
</style>

MyHeader.vue 

<template>
  <div>
    <input type="text"  @keyup.enter="mykeyup($event)">
  </div>
</template>
<script>
/* eslint-disable */
import {nanoid} from 'nanoid'
export default {
  name:"MyHeader",
  props:['getobj'],
  data(){
    return{
      "text":""
    }
  },
  methods:{
    mykeyup(event){
      if(event.target.value){
        let text= event.target.value
        this.text=text
        let newobj= {id:nanoid(),title:this.text,done:false}
        // 通知app组件去添加一个newobj
        this.getobj(newobj)
        event.target.value=''
      }
    }
  },
  
}
</script>
<style scoped>
input{
  width: 400px;
  height: 36px;
  line-height: 36px;
  border: 1px solid #dedede;
  outline: none;
}
</style>

 MyList.vue

<template>
  <div class="list">
      <MyItem v-for="item in list"  :key="item.id" :deleteList="deleteList" :item="item" :checktodo="checktodo"/>
  </div>
</template>
<script>
/* eslint-disable */
import MyItem from './MyItem.vue'

export default {
  name:"MyList",
  components:{
    MyItem
  },
  props:['list','checktodo','deleteList'],
  data(){
    return{
      mylist:this.list,
      currtext:this.text
    }
  },
  mounted(){
  
    
  },
  

}
</script>
<style scoped>
.list{
  display: flex;
    justify-content: flex-start;
    align-items: flex-start;
    flex-direction: column;
}
</style>

 MyItem.vue

<template>
  <div>

    <div  class="item" >
      <input type="checkbox" :checked="item.done" @click="change(item.id)"> 
      <span v-show="!isEdit">{{item.title}}</span>
      <input v-show="isEdit" type="text" 
        :value="item.title" 
        @blur="handlebule(item,$event)">
      <button   @click="xgitem(item)"> 编辑</button>
      <button  @click="itemdelete(item.id)"> 删除</button>
    </div>
  </div>
</template>
<script>
/* eslint-disable */
export default {
  name:"MyItem",
  data(){
    return{
      ishide:"hide",
      isEdit:false
    }
  },
  props:['item'],
  methods:{
    divhover(){
      this.ishide="show"
     
    },
    leave(item,e){
      // this.$bus.$emit("updateList",item.id,e.target.value)
      this.ishide="hide"    
    },
    itemdelete(id){
      
      // this.deleteList(id)
      this.$bus.$emit("deleteList",id)
      // for (let index = 0; index < this.itemlist.length; index++) {
      //   if(this.itemlist[index].id==id){
      //     this.itemlist.splice(index,1)
      //   }
        
      // }
    },
    change(id){
      
      // this.checktodo(id)
      this.$bus.$emit("checktodo",id)
    },
    // 编辑
    xgitem(item){
      
      this.isEdit=true
    },
    // 失去焦点
    handlebule(item,e){
      this.$bus.$emit("updateList",item.id,e.target.value)
      this.isEdit=false
    }

  }
}
</script>
<style scoped>
.item{
  display: flex;
  width: 100%;
}
.item button{
  display: none;
}
.item:hover button{
  display: block;
}
.hide{
  display: none;
}
.isEdit{
  display: none;
}
.show{
  display: block;
}
</style>

 MyFooter.vue

<template>
  <div>
      <div><input type="checkbox" @change="checkAll" name="" :checked="isall" id="">   已完成{{countnum}},总共 {{ list.length }}      </div>
  </div>
</template>
<script>
/* eslint-disable */
export default {
  name:"MyFooter",
  props:['list','checkAllList'],
  data(){
    return{
      num:0
    }
  },
  methods:{
    checkAll(e){
      let status=e.target.checked
      console.log(status)
      this.checkAllList(status)
    }
  },
  computed:{
    countnum(){
      let i=0
      for (let index = 0; index < this.list.length; index++) {
        
        
        if(this.list[index].done){
          i+=1

        }
        
      }
      this.num=i
      return this.num
    },
    isall(){
     
      if(this.num==this.list.length&&this.num>0){
        return true
      } else{
        return false
      }
    }
  }
}
</script>
<style scoped>

</style>

子传父的三种方法

1,:zcf1="zcfmeth1"

2, @zcf2="zcfmeth2"

3,    this.$refs.fcz3.$on("zcf3",this.zcfmeth3)

 app.vue(父)

<template>
  <div id="app">
    <!-- 子传父方法1  方法2 v-bind-->
    <HelloWorld :zcf1="zcfmeth1"  @zcf2="zcfmeth2"/>
    
    <!-- 子传父方法3 $emit -->  
    <!-- 不加.native,不是原生事件,则为自定义事件 -->
    <Person ref="fcz3" @click.native="show"/>
    <hr/>

   
  </div>
</template>

<script>
/* eslint-disable */
import Person from './components/Person'
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  components: {
    Person,HelloWorld
  },
  data(){
    return{
      personSex:'male'
    }
    
  },
  mounted(){
   
  },
  methods:{
    zcfmeth1(getnum){
        console.log("getnum:"+getnum)
    },
    zcfmeth2(getnum){
      console.log("getnum2:"+getnum)
    },
    zcfmeth3(getnum){
      console.log("getnum3:"+getnum)
    },
    show(){
      console.log("原生事件")
    }
  },
  mounted(){
    // zcf2触发的时候,调用zcfmeth3方法
    // this.$refs.fcz3.$on("zcf3",this.zcfmeth3)
    this.$refs.fcz3.$once("zcf3",this.zcfmeth3)
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
}
</style>

 HelloWorld.vue


<template>
  <div class="hello" >
    <p >HelloWorld</p>
   <button @click="getValue1">子传父</button>
   <button @click="unbind">解绑事件</button>
   <button @click="death">销毁当前组件的实例</button>
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';

export default {
  name: 'HelloWorld',
  props: ['zcf1'],
  data(){
    return{
      num:1,
    }
  },
  methods:{
    getValue1(){
      // 方法1
      this.zcf1(this.num)
      // 方法2
      this.$emit("zcf2",this.num)
     

    },
    unbind(){
      // this.$off("zcf2")//解绑一个事件
      // this.$off(["zcf2","shijian2"]);解绑多个事件
      this.$off()//解绑所有
    },
    death(){
      this.$destroy()//销毁当前组件的实例,销毁后所有该组件的事件都不奏效了
    }
    
  },
}
</script>
<style scoped lang="less">
[v-cloak]{
  display: none;
}
.hello{
  width: 100%;
  height: 100px;
  /* border: 1px solid #dedede; */
  text-align: left;
}
</style>

 pemainrson.vue


<template>
  <div class="hello" >
    <p >person</p>
    <button @click="getValue3">子传父</button>

  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
   
  },
  data(){
    return{
      num:1,
    }
  },
 methods:{
  getValue3(){
    // 方法3
    this.$emit("zcf3",this.num)
  }
 }

}
</script>
<style scoped>
[v-cloak]{
  display: none;
}
.hello{
  width: 100%;
  height: 100px;
  /* border: 1px solid #dedede; */
  text-align: left;
}
</style>

全局事件总线:任意组件通信(本质自定义事件)推荐

借助VueComponent.prototype.__proto__=Vue.prototype

 todos案例中是逐层传递

更改为

main.js

new Vue({

  render: h => h(App),

  beforeCreate(){

    Vue.prototype.$bus=this

  }

}).$mount('#app')

app.vue

 mounted(){

   this.$bus.$on("checktodo",this.checktodo)

   this.$bus.$on("deleteList",this.deleteList)

  },

  beforeDestroy(){

    this.$off(['checktodo','deleteList'])

  },

<template>
  <div id="app">
    <MyHeader ref="headerText"  :getobj="getobj"/>
    <MyList text="text"  :list="list" />
    <MyFooter :list="list" :checkAllList="checkAllList"/>
  </div>
</template>

<script>
/* eslint-disable */
import MyHeader from './components/todos/MyHeader.vue'
import MyFooter from './components/todos/MyFooter.vue'
import MyList from './components/todos/MyList.vue'

export default {
  name: 'App',
  components: {
    MyHeader,
    MyFooter,
    MyList
  },
  data(){
    return{
      "text":"",
      list:JSON.parse(localStorage.getItem("list"))||[],
    }
    
  },
  mounted(){
   this.$bus.$on("checktodo",this.checktodo)
   this.$bus.$on("deleteList",this.deleteList)
  },
  beforeDestroy(){
    this.$off(['checktodo','deleteList'])
  },

  methods:{
    getobj(obj){
      this.list.unshift(obj)
    },
    checktodo(id){
      for (let index = 0; index < this.list.length; index++) {
        if(this.list[index].id==id){
          this.list[index].done=!this.list[index].done
        }
      }
    },
    // 删除
    deleteList(id){
      console.log(id)
      this.list=this.list.filter((item)=>{
        return item.id!==id
      })
      console.log( this.list)
    },
    // 全选或者全部选
    checkAllList(status){
      for (let index = 0; index < this.list.length; index++) {
        this.list[index].done=status
      }
    }
  },
  watch:{
    list:{
      deep:true,
      handler(value){
        localStorage.setItem("list",JSON.stringify(value))
      }
    }
  },

}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
}
</style>

MyItem.vue 

 itemdelete(id){

     

      // this.deleteList(id)

      this.$bus.$emit("deleteList",id)

   

    },

    change(id){

     

      // this.checktodo(id)

      this.$bus.$emit("checktodo",id)

    }

<template>
  <div>

    <div  class="item" @mouseenter="divhover" @mouseleave="leave">
      <input type="checkbox" :checked="item.done" @click="change(item.id)"> 
      <span>{{item.title}}</span>
      <button :class="ishide" @click="itemdelete(item.id)"> 删除</button>
    </div>
  </div>
</template>
<script>
/* eslint-disable */
export default {
  name:"MyItem",
  data(){
    return{
      ishide:"hide",

    }
  },
  props:['item'],
  methods:{
    divhover(){
      this.ishide="show"
    },
    leave(){
      this.ishide="hide"    
    },
    itemdelete(id){
      
      // this.deleteList(id)
      this.$bus.$emit("deleteList",id)
      // for (let index = 0; index < this.itemlist.length; index++) {
      //   if(this.itemlist[index].id==id){
      //     this.itemlist.splice(index,1)
      //   }
        
      // }
    },
    change(id){
      
      // this.checktodo(id)
      this.$bus.$emit("checktodo",id)
    }

  }
}
</script>
<style scoped>
.item{
  display: flex;
}
.hide{
  display: none;
}
.show{
  display: block;
}
</style>

消息订阅

安装包 npm i pubsub-js

app.js

<template>
  <div id="app">
    <HelloWorld />
    <Person />
    <hr/>
  </div>
</template>

<script>
/* eslint-disable */
import Person from './components/Person'
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  components: {
    Person,HelloWorld
  },
  data(){
    return{
      personSex:'male'
    }
    
  },
  mounted(){
   
  },
  methods:{
   
  },
  mounted(){
   
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
}
</style>

 helloword给person传值

 HelloWorld.vue


<template>
  <div class="hello" >
    <p >HelloWorld</p>
  <button @click="sendperson">信息传给person</button>
  </div>
</template>

<script>

/* eslint-disable */
import Vue, { watch } from 'vue';
import pubsub from 'pubsub-js'
export default {
  name: 'HelloWorld',
 
  data(){
    return{
    }
  },
  methods:{
    sendperson(){
      pubsub.publish('hello',123)
    }
    
  },
}
</script>
<style scoped lang="less">
[v-cloak]{
  display: none;
}
.hello{
  width: 100%;
  height: 100px;
  /* border: 1px solid #dedede; */
  text-align: left;
}
</style>

person.vue


<template>
  <div class="hello" >
    <p >person</p>
    

  </div>
</template>

<script>

/* eslint-disable */
import pubsub from 'pubsub-js'
import Vue, { watch } from 'vue';
export default {
  name: 'HelloWorld',
  props: {
   
  },
  data(){
    return{
      
    }
  },
 methods:{
  
 },
 mounted(){
  this.pubid=pubsub.subscribe("hello",(mesName,param)=>{
    console.log("hello",mesName,param)
  })
 },
 beforeDestroy(){
  pubsub.unsubscribe(this.pubid)
 }

}
</script>
<style scoped>
[v-cloak]{
  display: none;
}
.hello{
  width: 100%;
  height: 100px;
  /* border: 1px solid #dedede; */
  text-align: left;
}
</style>

$nextTick(在节点更新后再执行)

<template>
  <div>

    <div  class="item" >
      <input type="checkbox" :checked="item.done" @click="change(item.id)"> 
      <span v-show="!isEdit">{{item.title}}</span>
      <input v-show="isEdit" type="text" 
        :value="item.title" 
        @blur="handlebule(item,$event)"
        ref="inputTitle">
      <button   @click="xgitem(item)"> 编辑</button>
      <button  @click="itemdelete(item.id)"> 删除</button>
    </div>
  </div>
</template>
<script>
/* eslint-disable */
export default {
  name:"MyItem",
  data(){
    return{
      ishide:"hide",
      isEdit:false
    }
  },
  props:['item'],
  methods:{
    divhover(){
      this.ishide="show"
     
    },
    leave(item,e){
      // this.$bus.$emit("updateList",item.id,e.target.value)
      this.ishide="hide"    
    },
    itemdelete(id){
      
      // this.deleteList(id)
      this.$bus.$emit("deleteList",id)
      // for (let index = 0; index < this.itemlist.length; index++) {
      //   if(this.itemlist[index].id==id){
      //     this.itemlist.splice(index,1)
      //   }
        
      // }
    },
    change(id){
      
      // this.checktodo(id)
      this.$bus.$emit("checktodo",id)
    },
    // 编辑
    xgitem(item){
      this.isEdit=true//还没有解析模板,所以inputTitle找不到
      // $nextTick会在下一次dom更新后再执行
      this.$nextTick(function(){

        this.$refs.inputTitle.focus()
      })
    },
    // 失去焦点
    handlebule(item,e){
      this.$bus.$emit("updateList",item.id,e.target.value)
      this.isEdit=false
    }

  }
}
</script>
<style scoped>
.item{
  display: flex;
  width: 100%;
}
.item button{
  display: none;
}
.item:hover button{
  display: block;
}
.hide{
  display: none;
}
.isEdit{
  display: none;
}
.show{
  display: block;
}
</style>

animate.css动画库

安装 npm i animate.css

引入 import 'animate.css'(哪个页面使用哪个页面引用的方法)

使用

 <transition name='fade'
         enter-active-class='animated swing' 
         leave-active-class='animated flash' >
  <div v-if="cssanimate">hello css animate</div>
</transition>
  <button @click='cssclick'>css动画</button>

axios和跨域问题

解决跨域

1.cors方法   后台开发配置响应头

2.jsonp   利用script src   只可解决get请求的跨域请求

3.代理服务器  

vue中使用vue-cli开启代理服务器

服务器与服务器之间不存在跨域问题

4.fecth

5.vue-resouce(目前很少用,vue1.0用的多,同axios使用一样,只需把 axios.get改成 this.$http即可)

代理服务器 解决跨域

axios (名字一样,优先匹配前端资源)

1.安装axios

npm install axios

2.安装脚手架(有则不需要安装)

        npm  install -g @vue/cli

        配置vue.config.js文件

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false,//关闭语法检测
  //开启代理服务器
 
    devServer: {
       proxy: { //api为前缀
        '/api': {
           target: 'http://localhost:5000/',
           pathRewrite:{'^/api':''},
            // ws: true, //支持websocket
            changeOrigin: true //用于控制请求中的host的值,ture  代理服务器“说谎”   false  真实
          }, 
        // '/foo': { target: 'http://localhost:5001/' } 
      }
    } 
  
})

3.页面引用

import axios from 'axios' 

// 全选或者全部选
    checkAllList(status){
     
      // axios.get("http://localhost:8080/api/student").then(
      axios.get("http://localhost:8080/text.txt").then(
        response=>{
          console.log("成功")
        },
        error=>{
          console.log("error")
        }
      )

      
    }

引入bootstrap

1.在public建文件夹css/bootstrap.min.css(只把bootstrap.min.css放在css文件夹中)   在index.html文件中引入,只用样式

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <link rel="icon" href="<%= BASE_URL %>css/bootstrap.min.css">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

2.npm i bootstrap@5.3.0-alpha1 (依赖jquery,需引入jquery)

搜索git用户列表

app.vue

<template>
  <div id="app">
    <Search @getText="getText" />
    <List :userlist="userlist" :loading="loading" />
  </div>
</template>

<script>
// https://api.github.com/search/users?q=xxx   cors解决了跨域
/* eslint-disable */
import axios from "axios";
import Search from "./components/search/Search";
import List from "./components/search/List";
export default {
  name: "App",
  components: {
    Search,
    List,
  },
  data() {
    return {
      text: "",
      userlist: [],
      loading: false,
    };
  },
  mounted() {
    // this.getlist("");
  },
  beforeDestroy() {},
  methods: {
    getlist(paras) {
      this.loading = true;
      axios.get("https://api.github.com/search/users?q=" + paras).then(
        (response) => {
          console.log("成功");
          this.loading = false;
          this.userlist = response.data.items;
        },
        (error) => {
          console.log("失败");
          this.loading = true;
        }
      );
    },
    getText(text) {
      this.getlist(text);
    },
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
}
</style>

Search.vue

<template>
  <div>
    <input type="text" v-model="text" /><button @click="gettext">搜索</button>
  </div>
</template>

<script>
export default {
  name: "Search",
  data() {
    return {
      text: "",
    };
  },
  methods: {
    gettext() {
      this.$emit("getText", this.text);
    },
  },
};
</script>

<style>
</style>

List.vue

<template>
  <div>
    <ul>
      <li v-for="item in userlist" :key="item.id">
        <img :src="item.avatar_url" alt="" />
        <p>{{ item.login }}</p>
      </li>
    </ul>
    <div class="loading" v-if="loading && userlist.length == 0">加载中</div>
  </div>
</template>

<script less>
export default {
  name: "List",
  props: ["userlist", "loading"],
  data() {
    return {};
  },
  mounted() {
    debugger;
    console.log(this.userlist);
  },
};
</script>

<style scoped lang="less">
ul {
  display: flex;
  width: 100%;
  flex-wrap: wrap;
  li {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    margin: 10px;
    img {
      height: 100px;
      width: 100px;
    }
  }
}
</style>

插槽

1.默认插槽

app.vue

<template>
  <div id="app">
    <div class="app-con">
      <!-- 驼峰命名引入方法 -->
      <defaut-slot title="书本">
        <img
          class="siot-img"
          src="https://docs.ruthout.com/files/pcsyrightup/20240722110643_71142.jpg?v=1721617604?v=1"
          alt=""
        />
      </defaut-slot>
      <defaut-slot title="爱好"></defaut-slot>
    </div>
  </div>
</template>

<script>
/* eslint-disable */
import axios from "axios";
import defautSlot from "./components/slot/DefautSlot";

export default {
  name: "App",
  components: {
    defautSlot,
  },
  data() {
    return {};
  },
  mounted() {},
  methods: {},
};
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
  .app-con {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
  }
}
</style>

 DefautSlot.vue

<template>
  <div class="slot">
    <h3>{{ title }}</h3>
    <!-- 插槽的样式可以写在本文件中,也可以写在父组件中 -->
    <slot>我是默认内容</slot>
  </div>
</template>

<script>
export default {
  name: "DefautSlot",
  props: ["title"],
};
</script>

<style scoped lang="less">
.slot {
  width: 300px;
  height: 500px;
  background-color: aquamarine;
  h3 {
    background-color: yellowgreen;
    text-align: center;
  }
  .siot-img {
    width: 100%;
  }
}
</style>
2.具名插槽 

app.vue

<template>
  <div id="app">
    <div class="app-con">
      <!-- 驼峰命名引入方法 -->
      <defaut-slot title="书本">
        <img
          slot="center"
          class="siot-img"
          src="https://docs.ruthout.com/files/pcsyrightup/20240722110643_71142.jpg?v=1721617604?v=1"
          alt=""
        />
        <!-- 方法1 -->
        <div slot="footer">
          <a href="">《王阳明心学》</a>
          <a href="">《清朝其实很有趣》</a>
        </div>
      </defaut-slot>
      <defaut-slot title="爱好">
        <!-- 方法2 -->
        <template v-slot:footer>
          <a href="">跳舞</a>
          <a href="">学习</a>
        </template>
      </defaut-slot>
    </div>
  </div>
</template>

<script>
/* eslint-disable */
import axios from "axios";
import defautSlot from "./components/slot/DefautSlot";

export default {
  name: "App",
  components: {
    defautSlot,
  },
  data() {
    return {};
  },
  mounted() {},
  methods: {},
};
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
  .app-con {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
  }
}
</style>

 DefautSlot.vue

<template>
  <div class="slot">
    <h3>{{ title }}</h3>
    <slot name="center"></slot>
    <slot name="footer"></slot>
  </div>
</template>

<script>
export default {
  name: "DefautSlot",
  props: ["title"],
};
</script>

<style scoped lang="less">
.slot {
  width: 300px;
  height: 500px;
  background-color: aquamarine;
  h3 {
    background-color: yellowgreen;
    text-align: center;
  }
  .siot-img {
    width: 100%;
  }
}
</style>
3.作用域插槽(子向父传数据)

app.vue

<template>
  <div id="app">
    <div class="app-con">
      <!-- 驼峰命名引入方法 -->
      <defaut-slot title="书本">
        <img
          slot="center"
          class="siot-img"
          src="https://docs.ruthout.com/files/pcsyrightup/20240722110643_71142.jpg?v=1721617604?v=1"
          alt=""
        />
        <!-- 方法1 -->
        <template slot-scope="{ book }">
          <div v-for="item in book" :key="item.id">
            <a href="">{{ item.name }}</a>
          </div>
        </template>
      </defaut-slot>
     
    </div>
  </div>
</template>

<script>
/* eslint-disable */
import axios from "axios";
import defautSlot from "./components/slot/DefautSlot";
export default {
  name: "App",
  components: {
    defautSlot,
  },
  data() {
    return {};
  },
  mounted() {},
  methods: {},
};
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
  .app-con {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
  }
}
</style>

DefautSlot.vue

<template>
  <div class="slot">
    <h3>{{ title }}</h3>
    <slot :book="book"></slot>
    <slot name="footer"></slot>
  </div>
</template>

<script>
export default {
  name: "DefautSlot",
  props: ["title"],
  data() {
    return {
      book: [
        { name: "book1", id: "1" },
        { name: "book2", id: "2" },
      ],
    };
  },
};
</script>

<style scoped lang="less">
.slot {
  width: 300px;
  height: 500px;
  background-color: aquamarine;
  h3 {
    background-color: yellowgreen;
    text-align: center;
  }
  .siot-img {
    width: 100%;
  }
}
</style>

vuex 

在vue中是实现集中式状态(数据)管理的一个vue插件

vue2中只能用vuex3版本(npm i vue@3或者npm install vuex@3 --force)

vue3中只能用vuex4版本(npm i vue)自动4版本,不用指定

src下面创建文件夹store>index.js

// 该文件用于创建vuex中最为核心的store
import Vue from 'vue'
// actions用于响应组件中的动作
import Vuex from 'vuex'

Vue.use(Vuex)
const actions={
  jia(context,value){
    
    console.log("actions");
    context.commit("JIA",value)
  }
}
// mutations用于操作数据(store)
// mutations里面方法一般大写
const mutations={
  // 对应方法1
  // addcount(state,count){
  //   state.count=count
  // },
    // 对应方法2
  ADDCOUNT(state){
    state.count++
  },
  JIA(state,value){
     console.log("mutations");
    state.dispnum=++value
  }
}
// state用于存储数据
const state={ 
  // 设置全局访问的state对象
    count:2,
    num:0,
    changeShow:true,
    dispnum:0
  }

// state中的数据进行加工
 const getters={
    //实时监听state的变化
    getCount(state){
      console.log(state);
      return state.count*10
    },
    isShow(state){
      return state.changeShow
    }
  }
// 创建并暴露store                        
export default new Vuex.Store({
  actions,
  mutations,
  state,
  getters
})

main.js中修改

import Vue from 'vue'

import App from './App'

// import Vuex from 'vuex'

import store from './store'


 

Vue.config.productionTip = false

console.log("@@@@@@@@@@@@"+App)

new Vue({

  render: h => h(App),

  store,

  beforeCreate(){

    Vue.prototype.$bus=this

  }

}).$mount('#app')

 文件中引用和修改

<template>
  <div id="app">
    <div class="app-con">
      从store中获取到的值
      <!-- {{ this.$store.state.count }} -->

      {{ count }}
      {{ num }}
      <br />
      调用 dispatch:
      {{ $store.state.dispnum }}
      <br />
      从store中getters获取到的值
      <!-- {{ this.$store.getters.getCount }} -->
      {{ getCount }}
    </div>
    <button @click="add">count++</button>
    <!-- 使用mapActions时需要传参数 -->
    <button @click="adddisp(n++)">n++</button>
  </div>
</template>

<script>
/* eslint-disable */
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
import store from "./store";
export default {
  name: "App",
  components: {},

  data() {
    return {
      n: 0,
    };
  },

  computed: {
    // 程序员自己写的方法
    // count() {
    //   return this.$store.state.count;
    // },
    // getCount() {
    //   return this.$store.getters.getCount;
    // },
    // 借助mapState和mapGetters
    //mapState({ count: "count", getCount: "getCount" })为对象,
    // 添加...就把里面的值展开放在computed中
    ...mapState({ count: "count", num: "num" }),
    ...mapGetters({ getCount: "getCount" }),
  },
  mounted() {},

  methods: {
    // 修改store中的值
    // add() {
    //   // 方法1
    //   // this.$store.commit("ADDCOUNT", this.$store.state.count++);
    //   //方法2;
    //   this.$store.commit("ADDCOUNT");
    // },
    // adddisp() {
    //   this.$store.dispatch("jia", ++this.n);
    // },
    // 借助mapMutations去生成对应的方法,方法中会调用commit去联系mutations
    ...mapMutations({ add: "ADDCOUNT" }),
    // 借助mapActions去生成对应的方法,方法中会调用dispatch去联系actions
    ...mapActions({ adddisp: "jia" }),
  },
};
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;

  justify-content: flex-start;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  flex-direction: column;
  .app-con {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
  }
  button {
    width: 80px;
    height: 38px;
  }
}
</style>

index.js模块化 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,我可以为您介绍一些Vue面试题。是一些常见的Vue面试题及其答案: 1. 什么是Vue.js? Vue.js是一个用于构建用户界面的渐进式JavaScript框架。它通过使用组件化的开发方式,使得构建复杂的Web应用变得更加简单和高效。 2. Vue.js的特点有哪些? - 简洁易学:Vue.js的API简单易懂,学习曲线较低。 - 组件化开发:Vue.js采用组件化的开发方式,使得代码可复用、可维护性高。 - 响应式数据绑定:Vue.js使用双向数据绑定机制,使得数据的变化能够实时反映在视图上。 - 虚拟DOM:Vue.js通过虚拟DOM的方式提高了页面渲染的性能。 - 生态系统丰富:Vue.js拥有庞大的社区和生态系统,有大量的插件和工具可供选择。 3. Vue.js中的生命周期钩子函数有哪些? Vue.js中的生命周期钩子函数包括:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy和destroyed。 4. Vue.js中的computed和watch有什么区别? - computed是计算属性,它根据依赖的数据动态计算出一个新的值,并将其缓存起来,只有依赖的数据发生变化时才会重新计算。 - watch是侦听器,它用于监听某个数据的变化,并在数据变化时执行相应的回调函数。 5. Vue.js中的v-if和v-show有什么区别? - v-if是条件渲染指令,根据表达式的真假来决定是否渲染DOM元素。当条件为假时,DOM元素不会被渲染到页面上。 - v-show也是条件渲染指令,但是它是通过控制元素的display属性来实现的。当条件为假时,DOM元素仍然存在于页面上,只是通过display属性隐藏起来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值