项目中遇到的vue知识点总结

1,652 阅读7分钟

本篇纯粹是为了学习时记录使用,有参考他人的,也有自己总结的,有错误或者不全面的地方会一直更新,也感谢大家帮忙指正~

1.v-bind的常见用法:

v-bind用来动态绑定属性值(使其能响应式更新)语法糖为:,与其对应还有v-on,用来监听事件,语法糖为@。

1.1. 绑定属性值

<div id="app">
  <p v-bind:title="title">hello World</p>
/div>
var vm = new Vue({
  el: '#app',
  data: {
    title: 'title content'
  }
})
// 最终渲染成:
<div>
  <p v-bind:title="title">hello World</p>
</div>

1.2. 绑定class:对象语法 && 数组语法

  • 对象语法:此时还可以与普通的class共存
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }" ></div>
data(){ // 只有再根组件中才能定义为对象,子组件的data必须是函数,保证子组件数据独立存储
    return {
        isActive: true,
        hasError: false
    }
}

更改isActive和hasError时,class列表相应地更新,另外:绑定的class对象不一定要写在模板里,直接写到data中也可以,此时还可以绑定一个返回对象的计算属性,即

<div v-bind:class="classObject"></div>
----------------------------------------
data() {
  return {
    isActive: true,
    hasError: false
  }
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.hasError,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}
渲染为:<div class="active"></div>
  • 数组语法:
<div v-bind:class="[activeClass, errorClass]"></div>
----------------------------------------------------
data() {
  return {
    activeClass: 'active',
    errorClass: 'text-danger'
  }
}
渲染为:<div class="active text-danger"></div>

另外: 数组内也可以使用对象语法,还可以使用三元表达式,用法灵活。

1.3. 绑定内联样式(用法与绑定class类似,此处省略)

1.4. 给图片添加url地址

<img class="box" :src="url"/>
var vm = new Vue({
  el: '.box',
  data: {
    url:'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png'
  }
})

2.父子组件间值的传递

2.1. 父组件向子组件传值(props):

在父组件中,创建一个自定义属性logoMsg,将值赋给logo;在子组件中,使用props来接收logo传递来的值(此时不需要加v-bind,如果需要动态负值则使用v-bind)。

补充

props特性:当父组件使用子组件,通过属性向子组件传值的时候,子组件声明了对父组件传递过来的属性的接收,有一一对应关系

非props特性:当父组件向子组件传递一个属性,1.子组件并没有props内容去接收这个内容,2.且此时这个属性会展示在子组件最外层的标签的html的属性之中

// 如:父组件定义并返回要传给子组件的值
<template>
  <div id="app">
    <HeaderDiv :logo="logoMsg"></HeaderDiv>
  </div>
</template>
-------------------------------------------
<script>
  import HeaderDiv from './components/header'
  export default {
    name: 'app',
    data(){
      return{
        logoMsg: 'WiseWrong'
      }
    },
    components: {
      HeaderDiv 
    }
  }
</script>
// 子组件通过props接收父组件传过来的值
<template>
  <header class="header">
    <div id="logo">{{logo}}</div>
    <ul>
      <li v-for="nav in navs">{{nav.li}}</li>
    </ul>
  </header>
</template>
---------------------------------------------
<script>
  export default {
    name: 'headerDiv',
    data(){
      return {
        navs: [
          {li: '主页'},
          {li: '日志'},
          {li: '说说'},
          {li: '主页'},
          {li: '相册'}
        ]
      }
    },
    props: ['logo']
  }
</script>

2.1.1.子组件通过props接收父组件的参数时:

!!!如果接收的参数是数组或者对象,不能直接使用,需要对数组或对象中的值进行遍历 例如:【仅展示逻辑】

// 父组件所传的参数
param = [{
  percent: 53,
  g: 1.5,
  width: 1.2,
  lor: 83,
}]
// 子组件
props: {//接收父组件传递的参数值(数组)
  param:{
    type: Array,
    default: null
  }
},
// 使用
console.log(this.param.percent) // 此时打印undefined
this.param.map(item=>{
  console.log(item.percent) // 打印值为53
})

2.2. 子组件向父组件传值$emit

2.2.1 通过事件传递携带参数

在子组件中this.$emit('transferUser',this.username)向父组件触发一个事件,父组件监听这个事件就行了

如下transferUser是父组件中需要监听的方法,msg是需要传递给父组件的信息

// 父组件监听并使用子组件传过来的数据
<template>
  <div id="app">
    <LoginDiv @transferUser="getUser"></LoginDiv>
    <p>用户名为:{{user}}</p>
  </div>
</template>
-------------------------------------------------
<script>
  import LoginDiv from './components/login'
  export default {
    name: 'app',
    data(){
      return {
        user: ''
      }
    },
    methods:{
      getUser(msg){
        this.user = msg
      }
    },
    components:{
      LoginDiv
    }
  }
</script>
// 然后子组件通过$emit触发transferUser事件
<template>
  <section>
    <div class="login">
      <label>
        <span>用户名:</span>
        <input v-model="username" @change="setUser"/>
      </label>
    </div>
  </section>
</template>
-----------------------------------------------------
<script>
  export default{
    name: 'login',
    data(){
      return {
        username: ''
      }
    },
    methods: {
      setUser: function() {
        this.$emit('transferUser', this.username)
      }
    }
  }
</script>

2.2.2 通过update:my-prop_name 的模式触发事件

子组件调用vm.$emit("update:show", false)更新父组件show的状态

父组件使用::show.sync="show"

//子组件
close(){
    this.isShow = false
    this.$emit('update:visible', false)
}

//父组件
<button @click='show = !show'></button>
<drag :visible='show'  @update:visible="val => show = val" />
// 父组件 用.sync 修饰符 可缩写为:
<button @click='show = !show'></button>
<drag :visible.sync='show'  />

注意:查看原因

2.3. 父组件通过$ref获取子组件数据,调用子组件的方法:

父组件在调用子组件的时候,将ref作用在子组件上,ref指向的是组件的实例,实例上的方法都可以调用 通过ref可以获取dom元素,若在引入的子组件中使用ref,则调用时获取到的是该组件

// 父组件
<template>
  <div class="parent">
  <div class="todo" @click='todo'></div>
    <child ref='child'></child>// ref 作用在组件上 指向的是组件的实例 实例上的方法都可以调用
  </div>
</template>
-----------------------------------------------------------------------------------------
<script>
  import child from '../base/child'
  export default {
    data(){ // 组件的data必须是函数
      return {
      }
    },
    methods:{
      todo(){
        console.log(this.$refs.child.msg)
          this.$refs.child.do()  // 子组件可以拿到父组件do()方法
        }
      },
      components:{
        child
      }
    }
</script>
// 子组件
<template>
  <div class="child">
  </div>
</template>
---------------------------
<script>
  export default {
    data() {
      return {
        msg: '我是子组件传递过来的数据'
      }
    },
    methods:{
      do(){
        alert('我是子组件的方法')
      }
    }
  }
</script>

补充:兄弟组件之间的传值:通过$emit$on组合实现

步骤1:建一个新的vue实例,类似一个站,连接着两个组件,也就是一个中央事件总线

// 方式1:
import Vue from 'vue'
export default new Vue
// 方式2:
import Vue from 'vue'
const $bus = new Vue()
export default $bus
// 方式3:
import { EventEmitter } from 'events'// nodejs事件的触发与监听
class Bus extends EventEmitter {
  constructor () {
    super()
  }
}
export default new Bus()

步骤2:再创建一个firstChild组件,引入bus,触发一个自定义事件,并传递数据

<template>
  <div id="firstChild">
    <h2>firstChild组件</h2>
    <button v-on:click='sendMsg'>向组件传值</button>
  </div>
</template>
<script>
  import bus from '../assets/eventBus'
  export dafault{
    methods:{
      sendMsg: function(){
        bus.$emit('userDefineEvent', 'this message is from firstchild')
      }
    }
  }
</script>

步骤3:另一个组件通过$on监听

<template>
  <div id="secondChild">
    <h2>secondChild组件</h2>
    <p>从firstChild接收的字符串参数:{{msg}}</p>
  </div>
</template>
<script>
  import bus from '../assets/eventBus'
  export dafault{
    data(){
      return {msg: '默认值'}
    },
    mounted(){
      var self = this
      bus.$on("userDefinedEvent", function(msg){
        self.msg = msg
      })
    }
  }
</script>

3.父子组件间的事件传递

参考链接 (方法3之后均未被引用过来)

3.1. 参考2.c节使用$ref,父组 件可调用子组件的方法(不再赘述)

3.2. 与2.b节类似,子组件通过$emit向父组件触发一个事件,子组件就可以调用父组件的方法

// 父组件监听子组件触发的tell事件,并执行fatherMethod函数
<template>
  <div class="parent">
    <child @tell='fatherMethod'></child>// 父组件中 在子组件上监听子组件派发的tell方法 然后调用函数 就能调用子组件的方法
  </div>
</template>

<script>
    import child from '../base/child'
    
    export default {
        data(){ // 组件的data必须是函数
          return {
          }
        },
        methods:{
            fatherMethod() {
                alert('我是父组件的know方法');
            }
        },
        components:{
            child
        }
    }
</script>
// 子组件向父组件触发事件
<template>
  <div class="child" @click='childClick'>
  </div>
</template>

<script>

export default {
  data() {
     return {
        msg: '我是子组件传递过来的数据'
     }
  },
  methods:{
     childClick(){
        this.$emit('tell') // 向父组件派发事件
     }
   }
}
</script>

3.3. 父组件直接把方法传入子组件中,在子组件里直接调用这个方法(也需要用到props属性)

// 父组件
<template>
  <div class="parent">
    <child :fatherMethod='fatherMethod'></child>// 父组件把方法传入子组件中,在子组件里直接调用这个方法
  </div>
</template>

<script>
import child from '../base/child'
    
export default {
  methods:{
     fatherMethod() {
       alert('我是父组件的know方法');
     }
   },
   components:{
     child
   }
}
</script>
// 子组件
<template>
  <div class="child" @click='childClick'>
  </div>
</template>

<script>

export default {
  props:{
     fatherMethod: {
        type: Function,
        default: null
     }
  },
  methods:{
     childClick(){
        this.fatherMethod()
     }
  }
}
</script>

4.vue中$的用法和含义

4.1. 参考链接

获取vue实例的参数,在实例内部用this.$data来获取,实例外部用vm.$data来获取~

vm.$watch('msg', function(newValue, oldValue)){ //监听vm.msg改变产生的回调 }

this.$data: vm的数据

this.$el: 当前el元素

this.$nextTick: 异步方法,等待渲染dom完成后来获取vm

this.$watch:监控

this.$set:后加的属性实现响应式变化

this.$refs:被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

4.2. 在Vue.prototype中使用:

在vue项目main.js文件中:Vue.prototype.$appName = 'My App', 这就相当于在原型上定义它们,使其在每一个Vue实例中可用(即变成了全局变量),在实例中使用:

new Vue({
  beforeCreate: function () {
    console.log(this.$appName)
  }
})

此时的$是在vue所有实例中都可用的属性的一个简单约定。好处是可以避免和已被定义的数据、方法、计算属性产生冲突。

4.3.Vue.$set方法,this.$setVue.$set用来深度访问数组,否则数组中数据改变了,页面不会同步渲染

详见13

5. 插槽的用法

5.1.普通插槽:

插槽就是子组件中的提供给父组件使用的一个占位符,用表示,父组件可以在这个占位符中填充任何模板代码,如HTML、组件等,填充的内容会替换子组件的标签。

5.2.具名插槽:

具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。

父组件中使用子组件,此时插槽位置只有一个,填充的内容是两个组件,通过v-if控制显示

<template>
  <Framer>
    <mainHead slot="header" v-if="winSize ==='small'"></mainHead>
    <renderHead slot="header" v-else></renderHead>
    <!-- <mainFooter slot="footer"></mainFooter> -->

  </Framer>
</template>
<script>
import Framer from '@/components/frame/mainFrame.vue'
import mainHead from '@/components/header/mainHead.vue'
import renderHead from '@/components/header/RenderHead.vue'

export default {
  name: 'MainWindow',
  components: { Framer, mainHead, renderHead },
  computed: {
    winSize () {
      return this.$store.getters.winSize
    }
  }
}
</script>

子组件定义插槽

<template>
  <div class="fullWindow" v-loading.fullscreen.lock="FullScreenLoading" :element-loading-text="LoadingText">
      <!-- 具名插槽 -->
      <slot name="header"></slot>
      <div class="body-container">
        <slot>
          <!-- 路由匹配到的子组件显示的地方 -->
          <router-view></router-view>
        </slot>
      </div>
  </div>

</template>

再举一例:

<div id="root">
  <body-content>
	<!-- <div class='header' slot="header"></div> --><!--此时第一个插槽位置被注释不填充内容-->
	<div class='footer' slot='footer'>11111111</div>
  </body-content>
</div>
<script>
   Vue.component('body-content', {
	 template: `<div>
		<slot name='header'><h1>哈哈哈哈哈哈哈</h1></slot>
		<slot name='footer'><h1>呵呵呵呵呵呵呵呵</h1></slot>
		</div>`
   })

   var vm = new Vue({
      el: '#root'
   })
</script>

渲染结果为:

<div id="root">
  <div>
    <h1>哈哈哈哈哈哈哈</h1>
    <div class="footer">11111111</div>
  </div>
</div>

总结: 具名插槽使用时:1.如果父组件只引入子组件,不填充插槽内容,就会展示子组件所有插槽的默认内容。

2.如果父组件想替换某一个插槽的内容,直接替换这一个插槽即可,如:<div class='footer' slot='footer'>11111111</div>即此时父组件填充了第二个插槽的内容,页面显示第一个插槽默认内容和第二个插槽由父组件填充的内容。

6.字符串模板

(每次项目中都不会使用,看了就忘,为了加深印象)

用法:xxx${变量}xxx,其中{}内部可以插入任何js表达式,还可以是一个对象、数组,甚至是一个函数。

模板字符串可以当作普通字符串使用,也可以用来在字符串中嵌入变量。

7.vue实例中的provide和inject

参考链接

provide:提供依赖,是一个对象,或者是一个返回对象的函数。里面呢就包含要给子孙后代的东西,也就是属性和属性值。 inject: 注入依赖和一个字符串数组,或者是一个对象。属性值可以是一个对象,包含from和default默认值。 provide和inject是成对使用的,比如项目中App.vue页提供依赖,主页面及其他子组件页面中都可以使用。

8.forEach和map函数的异同:

同:

  • 都是循环遍历数组中的每一项
  • 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组)
  • 匿名函数中的this都是指向window
  • 只能遍历数组 异:
  • map()函数会分配内存空间存储新数组并返回,forEach()不会返回数据
  • foreach()允许callback更改原始数组;map()返回新的数组,原数组不改变

9.lodash

是一个原生库,不需要引入其他第三方库,可以帮助剋发着提高效率,提升js原生方法的性能。其内部封装了很多数组、数字、对象、字符串等常见数据类型的处理函数,lodash使JavaScript变得更简单。

10.<component></component>的使用

<component></component>是vue框架自定义标签,它的用途是可以动态绑定我们的组件,根据数据的不同更换不同的组件

11.letconst

let定义的数组可以修改,const定义的数组不可修改

另外: const定义的对象可以修改。

12.vue动态渲染数组值

通过更新数组下标的方式改变数组不会生效,需要深度监听:

  1. 数组可以使用7个改变数组的方法(push,pop,shift,unshift,splice,sort,reverse)
  2. 或是改变引用,即整个数组地址空间变化,换一个数组赋值
  3. 利用实例的set方法;对象同理!vue.set()是全局方法,vm.$set()是vue实例的方法

13.vue中改变数组和对象

需要深度监听才能改变并渲染到页面上!

方式1:数组和对象都可以用Vue.set来实现:

方式2:

数组:this.$set(this.cardsData[0], index, 34)或者Vue.set(this.cardsData[0], index, 34)

数组还可以用12.中七个方法。

对象:this.$set(this.cardsData[0], 'brand', 34)或者Vue.set(this.cardsData[0], 'brand', 34)

14.vue实例中的this指向

在实例内部,可以直接用this获取到这个实例(的方法,属性等等),但如果是函数内部还嵌套一个函数(如闭包和回调函数),这时闭包内的函数直接用this就无法取到实例,而是获取到window对象,在闭包外面将this赋值给一个变量,从而闭包内就可以引用了。在ES6语法中无需这样,箭头函数就可以解决

// 回调函数
let _this = this
fse.readFile(path, 'utf-8', function(err, data){
  console.log(data)
  _this.param = []
}

上面写法等价于

fse.readFile(path, 'utf-8', (err, data)=>{
  console.log(data)
  this.param = []
}

15.与服务端通信函数的封装

16.异步函数promise的理解

参考 1.then的入参是一个函数,这个函数会return一个promise对象 2.函数定义的形式~在一个promise链中,只要任何一个promise被reject,promise就被破坏了,reject之后的promise链都不会再执行,而是调用.catch方法(因此在standard中,一定要在最后加上.catch,方便判断出哪个promise链出的问题)

17.全局状态

// 引用
computed:{
 isStsrt(){
 
}