1.计算属性如何使用
一般我们在写vue的时候,在模板内写的表达式非常便利,它运用于简单的运算,但是他也有一些复杂的逻辑,包括运算、函数调用等,那么就用到了计算属性,他依赖于data中数据变化的 data 中数据变化的时候 计算属性就会重新执行,视图也会更新。
2.计算属性的 set get 如何使用
每一个计算属性都包含一个getter 和一个setter ;绝大多数情况下,我们只会用默认的getter 方法来读取一个计算属性,在业务中很少用到setter,所以在声明一个计算属性时,可以直接使用默认的写法,不必将getter 和setter 都声明。但在你需要时,也可以提供一个setter 函数, 当手动修改计算属性的值就像修改一个普通数据那样时,就会触发setter 函数,
3.watch 如何使用
之前做一个H5的项目。需求是当用户在输入完了手机号和验证码之后,登录按钮才可以点击。 在没有使用vue之前,我们可能是通过input的change事件来判断,用户是否输入了内容,然后修改按钮的状态。现在有了vue,就省事了很多,我们只需要在watch中,监听数据模型的值改变即可。在input 上绑定一个v-mode="pass"绑定一个数据名, 在data里写入绑定的事件名,通过watch来监听输入内容的改变,但是如果,监听的是一个对象 里面有一个deep属性可以在选项参数中指定deep:true.也叫深度监听
<body>
<!-- 侦听器 -->
<div id="watch1">
<p>Ask a yes/no question:
<input type="text" v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var vm = new Vue({
el:'#watch1',
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(){
// 过Lodash限制操作pinlv的函数
//在这里我们希望限制访问yesno。wtf/api的频率
//AJAX请求直到用户输入完毕才会发出。
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'
})
}
}
})
</script>
4.计算属性和watch的区别
在我们运用vue的时候一定少不了用计算属性computed和watch
computed计算属性是用来声明式的描述一个值依赖了其它的值。当你在模板里把数据绑定到一个计算属性上时,Vue会在其依赖的任何值导致该计算属性改变时更新DOM。这个功能非常强大,它可以让你的代码更加声明式、数据驱动并且易于维护。
watch监听的是你定义的变量,当你定义的变量的值发生变化时,调用对应的方法。
就好在div写一个表达式name,data里写入num和lastname,firstname,在watch里当num的值发生变化时,就会调用num的方法,方法里面的形参对应的是num的新值和旧值,而计算属性computed,计算的是Name依赖的值,它不能计算在data中已经定义过的变量。
后加:
计算属性:我们可以将同一函数定义为一个方法而不是一个计算属性,两种方式的最终结果是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。只在依赖发生改变时它们才会重新求值。这就意味着只要message没有发生改变,多次访问reverseMessage会立即返回之前的计算结果,而不必再次执行函数。而method是每当触发重新渲染时,调用方法总会再次执行函数。
监听属性:大多数情况下计算属性更合适,但有时也需要一个自定义的侦听器。这就是为什么Vue通过watch选项提供了一个更通用的方法,来相应数据的变化,当 需要在数据变化时执行异步或开销较大的操作时,这个方式最为有用
5.prop验证,和默认值
我们在父组件给子组件传值的时候,为了避免不必要的错误,可以给prop的值进行类型设定,让父组件给子组件传值的时候,更加准确,prop可以传一个数字,一个布尔值,一个数组,一个对象,以及一个对象的所有属性。
组件可以为props指定验证要求。如果未指定验证要求,Vue会发出警告
比如传一个number类型的数据,用defalt设置它的默认值,如果验证失败的话就会发出警告。
6.插槽
单个插槽:在父组件写一个标签,在子组件通过slot来接受标签里的内容,他只能用一个slot。单个插槽可以放置在组件的任意位置,但是就像它的名字一样,一个组件中只能有一个该类插槽。
例如:写一个作为插槽的子组件模板navigationLink.vue
<a v-bind:href="url" class="nav-link">
<slot></slot>
</a>
在父组件中写插槽调用模板(插槽内可以包含任何模板代码,包括html。甚至其他组件)
<navigation-link url="/profile">
<!-- 添加一个font awesome图标 -->
<span class="fa fa-user"></span>
<!-- 添加一个图标组件 -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>
得到的结果:
<a url="/profile" class="nav-link">
<!-- 添加一个font awesome图标 -->
<span class="fa fa-user"></span>
<!-- 添加一个图标组件 -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</a>
具名插槽:在父组件标签写入slot,子组件里面写name名字,他们两个名字要相对应,才能通过名字在找到对应的位置。相对应的,具名插槽就可以有很多个,只要名字(name属性)不同就可以了。
假设一个<base-layout>组件的模板如下:
<!-- 对于这样的情况,<slot>元素有一个特殊的特性:name。这个特性可以来定义额外的插槽
我们还可以保留一个未命名插槽,这个插槽是默认插槽,也就是说他会作为所有未匹配到的插槽的内容的统一出口 -->
<div class="container">
<header><slot name="header"></slot></header>
<main><slot></slot></main>
<footer><slot name="footer"></slot></footer>
</div>
父组件调用如下
<!-- 在向具名插槽提供内容的时候,我们可以在一个父组件的<template>元素上使用slot特性 -->
<base-layout>
<template slot="header">
<h1>这是一个页头</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template slot="footer">
<p>这是一个尾</p>
</template>
</base-layout>
<!-- 另一种slot特性的用法是直接用在一个普通的元素上: -->
<base-layout>
<h1 slot="header">这是一个页头</h1>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<p slot="footer">这是一个尾</p>
</base-layout>
得到的结果都为:
<div class="container">
<header><h1 slot="header">这是一个页头</h1></header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer><slot name="footer"></slot></footer>
</div>
插槽的默认内容
例如,一个<submit-button>组件可能希望这个按钮的默认内容是Submit,但是同时允许用户覆写为“Save”、"Upload"或别的内容
,你可以在组件模板里的<slot>标签内部指定默认的内容来做到这一点,如果父组件为这个插槽提供了内容,则默认的内容submit会被替换掉
<button type="submit">
<slot>Submit</slot>
</button>
作用域插槽
举个例子,比如我写了一个可以实现条纹相间的列表组件,发布后,使用者可以自定义每一行的内容或样式(普通的slot就可以完成这个工作)。而作用域插槽的关键之处就在于,父组件能接收来自子组件的slot传递过来的参数,子组件与父组件的数据动态交互的一种常见案例
父组件中必须要有template元素,且必须有scope特性,scope特性中是临时变量名,
接收从子组件中传递上来的属性,属性可以是任意定义的。
<!-- 有时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽。例如一个简单的<todo-list>组件的模板可能包含如下代码 -->
<ul>
<li v-for="todo in todos" v-bind:key="todo.id">{{todo.text}}</li>
</ul>
<!-- 但是在我们应用的某些部分,我们希望每个独立的待办项渲染出和todo.text不太一样的东西。这也是作用域插槽的用武之地。 -->
<!-- 为了让这个特性成为可能,你需要做的全部事情就是将待办项内容包裹在一个<slot>元素上,然后将所有和其上下文相关的数据传递给这个插槽:在这个例子中,这个数据是todo对象: -->
<ul>
<li v-for="todo in todos" v-bind:key="todo.id">
<!-- 我们将每个todo准备一个插槽 -->
<!-- 将todo对象作为一个插槽的prop传入。 -->
<slot v-bind:todo="todo">
<!-- 回退的内容 -->
{{ todo.text }}
</slot>
</li>
</ul>
<!-- 现在当我们使用<todo-list>组件的时候,我们可以选择为待办项定义一个不一样的<template>作为替代方案,并且可以通过slot-scope特性从自足见获取数据: -->
<yodo-list v-bind:todos="todos">
<!-- 将slotProps定义为插槽作用域的名字 -->
<template slot-scope="slotProps">
<!-- 为待办项自定义一个模板, -->
<!-- 通过slotProps定制每个待办项 -->
<span v-if="slotProps.todo.isComplete">✓</span>
{{ slotProps.todo.text }}
</template>
</yodo-list>
<!-- 结构slot-scope -->
<!-- 如果一个js表达式在一个函数定义的参数位置有效,那么这个表达式实际上就可以被slot-scope接受。也就是说你可以在支持的环境下(单文件组件或现代浏览器),在这些表达式中使用ES2015解构语法 -->
<todo-list v-bind:todos="todos">
<template slot-scope="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{todo.text}}
</template>
</todo-list>
<!-- 这会使作用域插槽变得干净一些 -->
动态组件
在我们平时使用vue中的模板的时候,许多时候都是直接定义成一个固定的模板,但是,vue中提供了一个动态模板,可以在任意模板中切换,就是用vue中<component>用:is来挂载不同的组件。
我们在components中注册了三个模板,当我们点击当前按钮的时候,就会将模板切换模板,可以说是非常方便了。如果要把组件切换过程中的将状态保留在内存中,可以添加一个 keep- alive 指令参数,防止重复渲染DOM。
动态组件上使用keep-alive
<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
在一个多标签的界面中使用 is 特性来切换不同的组件:你选择了一篇文章,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示你之前选择的文章的,每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent 实例。
<component v-bind:is="currentTabComponent"></component>
当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。
重新创建动态组件的行为通常是非常有用的,但是在这个案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive> 元素将其动态组件包裹起来。
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
子组件访问父组件实例子 $parent
针对需要向任意更深层级的组件提供上下文信息时推荐依赖注入。
this.$parent
在子组件中判断this.$parent获取的实例是不是父组件的实例
在子组件中console.log(this.$parent) 打印出this.$parent
在父组件中console.log(this) 打印出this
看看打印出来的两个实例是不是同一个
如果是同一个 就可以在子组件中通过this.$parent.属性名和方法名,来调用父组件中的数据或者方法
父组件访问子组件变量 this.$refs.usernameInput
给子组件添加ref属性然后,通过vm.$refs来调用子组件的methods中的方法或者获得data
父组件: 在子组件中加上ref即可通过this.$refs.ref.method调用
$refs
只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs
。