本篇纯粹是为了学习时记录使用,有参考他人的,也有自己总结的,有错误或者不全面的地方会一直更新,也感谢大家帮忙指正~
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.$set或Vue.$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.let与const
let定义的数组可以修改,const定义的数组不可修改
另外: const定义的对象可以修改。
12.vue动态渲染数组值
通过更新数组下标的方式改变数组不会生效,需要深度监听:
- 数组可以使用7个改变数组的方法(push,pop,shift,unshift,splice,sort,reverse)
- 或是改变引用,即整个数组地址空间变化,换一个数组赋值
- 利用实例的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(){
}