1.响应式数据
/*
vue初始化时,会遍历data的所有属性
并使用Object.defineProperty方法将这些属性转为getter/setter
使vue能够追踪依赖 ,当属性访问或修改时通知变更
所以,属性必须在data对象上才会是响应式的
*/
// 1.对于已经创建的实例,vue不允许动态添加根级别的响应式属性
// 2.可以使用Vue.set或this.$set方法向嵌套对象添加响应式属性
Vue.set(vm.someObject,'b',2)
this.$set(this.someObject,'b',2)
// 3.若需要对已有对象赋值多个新属性,应该用源对象与要混合的对象属性一起创建一个新的对象
this.someObject = Object.assign({},this.someObject,{a:1,b:2})
2.Vue.nextTick(callback)
/*
Vue在更新DOM时是异步执行的
当监听到数据变化,Vue将开启一个队列,并缓冲同一事件循环中发生的所有数据更改
在下一个事件循环'tick'中,Vue刷新队列并执行实际工作
*/
Vue.component('example', {
template: '<span>{{ message }}</span>',
data: function () {
return {
message: '未更新'
}
},
methods: {
updateMessage: function () {
this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
//方式一
this.$nextTick(function () {
console.log(this.$el.textContent) // => '已更新'
})
// 方式二:$nextTick()返回一个Promise对象
await this.$nextTick()
console.log(this.$el.textContent) // => '已更新'
}
}
})
3.样式scoped实现私有化样式
每个html的DOM节点添加一个不重复的data属性,表示唯一性
每个css选择器的末尾添加一个data属性选择器,来私有化样式
如.button[data-v-2311c06a]{}
注:添加scoped则父组件无法修改子组件的样式
【v-html动态创建的DOM不受scoped的影响,可以采用深选择器】
解决方法:
1.采用全局属性和局部属性混合的方式
2.每个组件在外层添加一个唯一的class来区分不同的组件
3.使用深选择器deep
<!-- 子组件 -->
<div class="gHeader">
<div class="name"></div>
</div>
<!-- 父组件 -->
<template>
<div id="app">
<gHeader></gHeader>
</div>
</template>
<style lang="css" scoped>
.gHeader /deep/ .name{ <!--第一种写法 deep-->
color:red;
}
.gHeader >>> .name{ <!--第二种写法 >>> -->
color:red;
}
</style>
4.父子组件通信、兄弟组件通信
<!--
父子组件通信:props、$emit
兄弟组件通信:eventBus,下面这个案例就是针对此问题的
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>兄弟组件通信</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="container">
<p>{{msg}}</p>
<child1></child1>
<hr>
<child2></child2>
</div>
<script>
// 借助于一个公共的Vue的实例对象,不同的组件可以通过该对象完成事件的绑定和触发
// new一个对象,兄弟间的通信,将借助他事件绑定和触发来实现
var bus = new Vue();
// 组件一
Vue.component("child1", {
methods: {
sendToXiongEr: function () {
bus.$emit("msgToXiongEr", "哈哈,光头强来了");
}
},
template: `
<div>
<h1>我是熊大</h1>
<button @click="sendToXiongEr">Click Me</button>
</div>
`
})
// 组件二
Vue.component("child2", {
template: `
<div>
<h1>我是熊二</h1>
<p>{{message}}</p>
</div>
`,
mounted: function () {
var that = this;
bus.$on("msgToXiongEr", function (msg) {
that.message = msg
})
},
data() {
return {
message: ''
}
}
})
new Vue({
el: "#container",
data: {
msg: "Hello VueJs"
}
})
</script>
</body>
</html>
5.生命周期
6.computed、watch、方法
/*
computed计算属性
初衷:用于简单的运算,对于复杂的逻辑应该使用计算属性
避免在模板中放入太多的逻辑让模板过重难以维护
*/
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
// reversedMessage的值始终取决于message,所以当message改变时,其依赖项也改变
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
})
/*
方法与依赖项的区别:
方法也可以达到计算属性的效果
差别:计算属性是基于他们的响应式依赖进行缓存的,即只有响应式依赖发生改变才会重新求值
方法在于即使没改变,只要使用就会重新求值
*/
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
/*
侦听属性与计算属性:
虽然计算属性在大多数情况下更适合,但有时也需要自定义侦听器
当需要在数据变化时执行异步或开销较大的操作时,这个方式最有效
*/
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>
7..ref
<!--
ref用来给元素或子组件注册引用信息
如果在普通的DOM元素上使用,引用指向的就是DOM元素
若在子组件上,引用指向的就是组件实例
this.$refs.调用
注意点:
1.ref本身是作为渲染结果被创建的,初始渲染的时候不能访问,它们还不存在
2.$refs也不是响应式的,因此不应该试图用它在模板中做数据绑定
-->
<p ref="p">Hello</p>
<child-component ref="child"><child-component>
8.v-cloak
<ul v-for="item in items">
<li>{{ item.name }}</li>
</ul>
<!--
当我们使用vue从后台读取的数据时或者是刷新页面的时候
因为响应问题可能会闪现一下{{item.name}} 这个vue.js模板变量
这样给用户带来了不好的体验,这时候v-cloak 就要派上用场了
v-cloak
包含 v-cloak 属性的 html 标签在页面初始化时会被隐藏
在 vuejs instance ready 之后,v-cloak 属性会被自动去除,也就是对应的标签会变为可见
-->
<ul v-cloak v-for="item in items">
<li>{{ item.name }}</li>
</ul>
[v-cloak] {
display: none;
}
Computed property was assigned to but it has no setter
/* 原因:
computed定义的属性只有get没有设置set,而这个属性又在其他地方进行了赋值,导致提示该错误
解决方案:
*/
// 方案一:设置get/set
computed: {
searchVal: {
get(){
return ...
},
set(val){
... = val
}
}
}
// 方案二:使用val/change
computed: mapState([
'enableAudio'
])
<el-switch
:value="enableAudio"
:disabled="!enableAudio"
@change="changeAudio($event)"
></el-switch>
changeAudio (val) {
this.$store.commit('setAudio', val)
}
网友评论