vue 知识点
-
Vue 中的 slot:
概念:槽/slot是组件在模板中为调用者预留的位置,使用<slot>
元素声明一个 槽。在最终的视图中,调用者模板中被调用组件的内容,将填充<slot>
元素 占据的位置,形成最终的模板。
一篇比较好的介绍文章:
深入理解vue中的slot与slot-scope:https://segmentfault.com/a/1190000012996217 -
Vue 中的 slot:
- 在Vue中,slot是一个很有用的特性,可以用来向组件内部插入一些内容。slot就是“插槽”的意思,用大白话说就是:定义组件的时候留几个口子,由用户来决定插入的内容。
- 假如我们有一个程序实例,使用相同的组件
<app-child>
两次。在每个子组件内部,我们需要一些相同的内容以及不同的内容。对于要保持一致的内容,我们使用一个标准的 p 标签,而对于要切换的内容,我们放在空的<slot></slot>
标签中。
<script type="text/x-template" id="childarea">
<div class="child">
<slot></slot>
<p>It's a veritable slot machine!<br>
Ha ha aw</p>
</div>
</script>
然后在程序实例中,我们可以在在 <app-child>
组件标签中传递内容,它会自动填充到 slots 中:
<div id="app">
<h2>We can use slots to populate content</h2>
<app-child>
<h3>This is slot number one</h3>
</app-child>
<app-child>
<h3>This is slot number two</h3>
<small>I can put more info in, too!</small>
</app-child>
</div>
- slots 中也可以有默认内容。如果要在 slot 中写内容,而不是写
<slot></slot>
,你可以这样填充:
<slot>I am some default text</slot>
如果你没有在 slot 中填充其它内容,就会显示默认文本。
- 你也可以使用具名 slot 。如果一个组件中有两个 slot, 可以通过添加 name 属性区分它们
<slot name="headerinfo"></slot>
,并且通过特定的名称访问 slot<h1 slot="headerinfo">I will populate the headerinfo slot!</h1>
。这非常有用。如果有多个命名的 slot 而有一个没有命名,Vue 命名的内容填充到命名的 slot 中,而剩余的内容将填充到未命名的 slots 中。
- vue 中 slot 的一个简单例子:
比如你自己做了个一个button组件,在根组件里注册为vButton,从而复用。
那么各个button上的文字肯定是不同的,但是这些文字大部分情况下也是不需要动态更新的,那么就不必用props之类的方法从根组件向子组件传递文字,直接用slot即可。
button组件假如是这样:
<template>
<button>
<slot></slot>
</button>
</template>
根组件就可以这样用它:
<v-button>按钮文字</v-button>
- createElement 中,attrs 和 props 的区别:
官方地址:https://cn.vuejs.org/v2/guide/render-function.html#深入-data-对象
// 正常的 HTML 特性
attrs: {
id: 'foo'
},
// 组件 props
props: {
myProp: 'bar'
}
-
vue子组件里类型为Function的props,父组件使用时要写在methods里
该用法例子(子组件):https://github.com/cag2050/vue_tables_xlsx_demo/blob/master/src/components/DataTablesExportExcel.vue -
vue项目中,不用写CSS的兼容性代码。
因为vue-loader在编译.vue文件的时候,使用了Postcss的工具,它会给有兼容性问题的属性添加兼容性代码。
它是根据can i use官网写的代码。
写在内才会生效。在html中添加style属性是不会添加兼容性代码的。 -
计算属性(computed)不能直接设置值;
如果直接设置值,报错:
Computed property "xxx" was assigned to but it has no setter.
-
一、仅仅是想通知某个对象去更改状态,建议使用事件的方式
1.父子组件之间的事件通讯,通过在父组件监听对应的事件名,子组件触发的方式。
2.非父子组件采用Event Bus的方式
二、数据在组件之间的共享
1.中大型应用使用vuex
2.应用场景比较少的情况,父子组件采用props,非父子组件Event Bus传递数据 -
编写全局插件的方式:
方式 | 写法 |
---|---|
Vue.mixin | Vue.mixin({}) |
Vue.prototype | Vue.prototype.<func_name> =function() |
Vue.filter | Vue.filter(<func_name>,function(){}) |
Vue.directive | Vue.directive('myfocus', {}) |
- vue开发插件:
- 定义全局插件:helper.js
import Clickoutside from 'element-ui/lib/utils/clickoutside'
export default {
install (Vue, options) {
Vue.mixin({
directives: {
Clickoutside
},
data () {
return {
someValue: 'some value'
}
}
})
Vue.prototype.getDate = function () {
let end = new Date()
let start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
return [start, end]
}
Vue.filter('vcntFormat', function (cnt) {
return cnt >= 100000 ? Math.floor(cnt / 10000) + '万' : cnt
})
}
}
- main.js里引入并使用:
import Helpers from './helpers'
Vue.use(Helpers)
-
全局注册混合对象:
Vue.mixin({Object})
全局注册混合对象后,会影响到 所有 之后创建的 Vue 实例。 -
vue组件使用中,PascalCase 是最通用的 声明约定 而 kebab-case 是最通用的 使用约定。
在 HTML 模板中,组件名请使用 kebab-case 形式:
<my-component></my-component>
- 定义 transition-group 的过渡效果。
stylus 语法:
// 一定时间内,针对opacity的transition完成
.fade-enter-active
.fade-leave-active
transition opacity 1s ease
// 开始enter的时候,透明度为0,变化为1;开始leave的时候,透明度为1,变化为0
// 此处只需要写进入元素的开始enter:v-enter、离开元素的leave结束:v-leave-to(v-是这些过渡类名的前缀)
.fade-enter
.fade-leave-to
opacity 0
https://cn.vuejs.org/v2/guide/transitions.html#过渡的类名
- 当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:
- 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
- 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
- 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)
- on和emit的事件必须是在一个公共的实例上,才能触发。
我的解决方案是:
新建bus.js
import Vue from 'vue'
export var bus = new Vue()
App.vue里created方法里定义事件
import { bus } from 'bus.js'
// ...
created () {
bus.$on('tip', (text) => {
alert(text)
})
}
Test.vue组件内调用
import { bus } from 'bus.js'
// ...
bus.$emit('tip', '123')
- 每个
<transition-group>
的子节点必须有 独立的 key ,动画才能正常工作
https://cn.vuejs.org/v2/api/#transition-group
<transition-group>
渲染一个真实的 DOM 元素。默认渲染<span>
,可以通过 tag 属性配置哪个元素应该被渲染。
下面这个例子渲染的是<ul>
元素
<transition-group name='fade' mode='out-in' tag='ul'></transition-group>
- vue绑定类和样式:
:style="this.type === '1' ? 'margin-top:565px' : ''"
:class="this.type === '1' ? '[class-name]' : ''"
-
v-model 绑定的值一定要能访问,可以是data中的值或mapstate里的值
-
vue调试
改store里的接口返回值,来制作模拟数据,不用改页面代码,这样方便调试。 -
vue编写思路:
mapstate里值为null时,外层元素显示loading;state里值不为null时,各内层元素v-show绑定computed里某函数,该函数设置各内层元素的值,最后返回true -
问:vue ajax初始化数据是应该在created()里面还是放在mounted()里面?
答:根据情况,一般放到created里面就可以了,这样可以及早发请求获取数据;
如果有依赖dom必须存在的情况,就放到 mounted(){this.$nextTick(() => { /* code */ })} 里面 -
css 添加 scoped 属性作用:
不要过度依赖scoped,scoped 不好维护,良好的css层级和嵌套规则完全够用。
父组件的有作用域的CSS和子组件的有作用域的CSS将同时影响子组件。
有作用域的样式对其他部分没有影响。
Vue 文件格式可以支持局部 CSS,只要在 style 标签上加上一个 scoped 属性,样式只会影响当前组件及子组件。 -
问:vue 能自动识别组件的名字?比如:组件文件名是 ClipList,在 html 中写 clip-list、c-liplist、cli-plist 都可以?
答: -
vue 获取元素,全部定义 ref 属性来获取。
<div ref="div1"></div>
通过 this.$refs.div1 来得到这个元素。
-
vue2.0 不支持 contenteditable="true"属性,解决办法:
https://jsfiddle.net/cag2050/knodLosn/ -
vue中引入图片,必须用 require 或 import。
import scene1 from '../assets/scene1.jpg'
- 在子组件中,props里定义的属性,比如:
props: {
list: Array
}
在子组件中,可以直接这样访问父组件传到子组件的这个值:this.list
- 问:在 Vue.js 中使用第三方库有哪些方法?
答:4种方法。
- 在项目中添加第三方库的最简单方式是将其作为一个全局变量, 挂载到 window 对象上
- 一个简单的方式是在每一个需要该库的文件中导入
- 在 Vuejs 项目中使用 JavaScript 库的一个优雅方式是将其代理到 Vue 的原型对象上去
- 如果你想在多个项目中使用同一个库, 或者想将其分享给其他人, 可以将其写成一个插件
-
子组件props中声明的值,可以使用 this.[key] 访问。
-
问:为什么Vue组件中的data是一个函数,而Vue构造器var vm = new Vue({})里的data是一个对象?
答:组件中的data之所以是函数,而不是对象,是因为每个组件都是相互独立的,如果它们共用一个对象,在更改一个组件数据的时候,会影响其他组件。如果是函数的话,每个组件都有自己独立的数据。相互之间不会影响。
官方解释:https://cn.vuejs.org/v2/guide/components.html#data-必须是函数 -
通过Vue构造器传入的各种选项大多数都可以在组件里用。 data 是一个例外,它必须是函数。
-
通过为每个组件返回全新的 data 对象来避免组件共享同一个 data。
-
watch可以监控组件data中的属性,或vuex中...mapState中的内容。
-
computed里的函数名,随便写,只要函数中有值(值可以是:data中的属性,或vuex中...mapState中的内容)变化,就会计算。
-
计算属性:函数中,只要有值变化,就会计算
-
Vue生命周期图示:
-
插值:
文本:{{ message }};
纯html:v-html="xxx";
属性:v-bind:id="xxx";
使用 JavaScript 表达式:{{ ok ? 'YES' : 'NO' }}
过滤器:{{ message | capitalize }} -
指令:
参数:v-bind:href="xxx"; v-on:click="xxx";
修饰符:v-on:submit.prevent="xxx" -
缩写:
v-bind 缩写,使用:(冒号)
<a v-bind:href="url"></a>
<a :href="url"></a>
v-on 缩写,使用@
<a v-on:click="doSomething"></a>
<a @click="doSomething"></a>
-
computed和method:优先考虑使用computed
计算属性computed是基于它的依赖缓存。计算属性只有在它的相关依赖发生改变时才会重新取值。
每当重新渲染的时候,method 调用总会执行函数。 -
访问vue组件的data:
this.$data
访问data里的数据:
this.$data.[key] 或直接 this.[key]
- vue实例export default { }写法:
name: 'profile',
data () {
return {
}
},
created () {
this.$nextTick(function () {
})
},
filters: {
nullFilter: (value) => {
return value === '' ? '暂无信息' : value
}
},
computed: {
show: function () {
return this.$store.state.user !== null && this.$store.state.user.auth !== null
}
},
methods: {
}
-
computed、methods、watch不能用es6的箭头函数,filters可以用es6的箭头函数。
-
computed函数名,跟template里的值,是一一对应的。
-
vue监控(watch)对象。watch可以监控组件data中的属性,或vuex中...mapState中的内容(举例:下面第二段代码的user)
watch: {
user (user) {
this.form.nick = user.nick === '' ? '暂无信息' : user.nick
},
form: { // form是对象,使用这种写法
handler (form) {
console.log(form.nick)
},
deep: true
}
},
...mapState({
user: state => state.user.auth
})
-
一个页面中有多个组件的数据初始化,判断方法:
1.所有组件都初始化好之后,再显示;
三个条件:获取数据的方法写在created里;dom最外层写v-if="show";show方法写在computed里,判断所有数据都有;
2.部分组件有数据后,就显示,局部刷新的数据写在computed里。 -
new Vue的多种方法:
new Vue({
el: '#app',
render: h => h(App)
})
render: h => h(App) 含义:
=> 是ES6的箭头语法
// ES5
render: function(h) {
return h(App);
}
// ES6
render: h => h(App);
render是Vue 2.0新增的函数,可以直接给绑定节点渲染一个vue组件,如果在Vue 1.x下,就应该使用
new Vue({
el: '#app',
components: { App }
});
然后在页面中写入标记:
<div id="app">
</div>
-
vue实例四种写法
-
vue组件间传递数值:
初学者常犯的一个错误是使用字面量语法传递数值:
<!-- 传递了一个字符串"1" -->
<Parent some-prop="1"></Parent>
因为它是一个字面 prop ,它的值以字符串 "1" 而不是以实际的数字传下去。
如果想传递一个实际的 JavaScript 数字,需要使用 v-bind ,从而让它的值被当作 JavaScript 表达式计算:
<!-- 传递实际的数字 -->
<Parent v-bind:some-prop="1"></Parent>
- 使用子组件的方式:
1)父组件内components引入;
2)通过在路由中配置children