Vue 选项 / 数据,DOM
每个vue应用都是通过构造函数Vue创建的一个Vue的根实例启动的,在实例化Vue时,需要传入一个选项对像,它可以包括是数据,模板,挂载元素,方法,生命周期函数等选项
const vm=new Vue({ })
el
提供一个在页面上已经存在的DOM元素作为实例的挂载目标,可以是CSS选择器,ID选择器等,也可以是一个HTMLElement实例
new Vue({
el:"#app"
})
如果我们声明了一个vue实例,但是没有传入el属性,那么该实例会处于未挂载的状态,没有关联的DOM属性,可以使用$mount来实现手动挂载
const vm=new Vue({
data:{
say:"hellow world"
}
}).$mount("app");
console.log(vm.$data.say)
data
类型: object | function
限制:在组件中对象必须是function格式
对象的格式必须是纯粹的对象(含有零或多个key/value的键值对),可以理解为data应该只能是数据,不推荐其它形似
不要对data属性使用箭头函数,在data中this的指向应该是Vue实例
new Vue({
el:"#app",
data:{
name:"tom"
}
})
实例创建之后,可以通过vm.$data访问原始数据对象,在实例内部可以直接通过this.data[属性]来获取指定的属性
<p>{{this.test}}</p>
<p>{{test}}</p>
<p>{{this.$data.test}}</p>
new Vue({
...
data(){
return {
test:"测试"
}
}
})
props
类型: Array | Object
props可以是数组或对象,用来接收来自父组件的数据,props可以是简单的数组,或者是用对象作为替代,对象允许接收高级选项,如类型检测,自定义校验和设置默认值
//简单语法
Vue.compoment("props-demo",{
props:['size','myMessage']
})
//对象语法
//在对象语法中可以进行类型检测,设置默认值或者自定义校验规则
//类型检测可以是Js中的简单数据类型和复杂数据类型,如果从父组件中获取的值的类型不符合的话,命令依然会执行,但是在控制台中会报错
Vue.component("props-demo",{
props:{
props_a:{
type:'Number',
//type 类型可以是String Number Boolearn Function Fbject Array Symbol 'null'表示允许传入任意值
//也可以组合传入 [String,Number] ,表示是多种类型
default:10,
//设置的默认值,如果在父组件中没有获取值的话会展示默认值
//如果我们设置类型为Object/Array,default的值必须是一个函数,default(){ return{ } }
required:true,
//表示必传
validator: function (value) {
//设置自定义校验规则,value为获取的父组件的数据,如果不符合校验条件也会在控制台报错
return value > 10
}
}
}
})
在模板中如果要动态的绑定父组件的数据到子组件中,需要使用v-bind,在使用动态绑定后,如果父组件的数据发生变化,该变化也会传导给子组件
<child :get-parent-msg="parentMsg"></child>
如果不使用动态绑定,那么我们最终获取到的数据只是在标签中写入的字符串
<child get-parent-msg="parentMsg"></child>
<!--最后我们在子组件中获取到的只是字符串parentMsg,并不是父组件中data的parentMsg变量的值-->
由于html的特性是不区分大小写的,所以当使用的不是字符串模板时,使用驼峰命名法的prop需要转换为相对应的短横线相隔开的命名格式
<child :get-parent-msg="parentMsg"></child>
Vue.component("child",{
props:["getParentMsg"]
})
注意,每一次父组件数据更新时,子组件的所有props都会更新为最新值,如果我们在子组件直接修改props的值,控制台会报错
虽然明确给组件定义props是传参的推荐方式,但实际组件可以接收任意传入的特性,这些特性都会被添加到组件根元素上,例如在使用Botstrap时,我们需要在某一个组件上添加一个data-3d-data-picker特性,这时可以直接把属性添加到组件上,不需要事先定义prop
<组件 data-3d-date-picker='true'><组件>
添加的属性data-3d-data-picker会自动被添加到组件的根元素上
computed
我们在模板内可以运用表达式,但是如果在模板内放入太多的逻辑代码会让后期的维护变得十分困难,vue为我们提供了computed来处理复杂逻辑,例如:
<p>{{msg.split('').reverse().join("")}}</p>
<!--对于这样的逻辑,我们可以将其放置到computed中来进行处理-->
computed:{
reverse:function () {
return this.msg.split("").reverse().join("");
}
}
//computed的变量会挂载到实例本身,可以直接使用
<p>{{reverse}}</p>
在上面的例子中,reverse的值依赖于msg,使用计算属性,在msg的值发生变化时,reverse的值也会相应的发生变化
对于在computed中设置监测数据变化方法,如果我们使用methods同样可以实现
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
})
//转化为method方式
var vm=neww Vue({
el:'#example',
data:{
message:"hello"
},
methods:{
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
})
//然后在页面中调用reversedMessage()方法即可
{{reversedMessage()}}
两者的区别在于computed是会基于他们的依赖进行缓存,只有在它的依赖发生改变时才会重新求值
这意味着如果数据没有发生变化,即使多次访问计算机也只会返回之前的计算结果,而不必再次执行函数操作
而如果使用methods,只要重新渲染methods就会执行该函数
计算属性默认只有getter,但是我们也可以提供一个setter
var vm = new Vue({
el: ".test",
data: {
a: 1
},
methods:{
click(){
this.b=2;
}
},
computed: {
b:{
get: function () {
return this.a+1;
},
set: function (newValue) { //参数是必须的
this.a = newValue-1;
}
}
}
})
//计算属性中默认是只有get的,我们在平时使用的时候大部分都是通过改变a的值来改变b的值
//在设置了set之后,如果我们改变b的值,那么a的值也会相应的改变
//值得改变的顺序是首先调用set改变a的值,在a的值发生改变后会调用get,b的值同时发生改变
methods
大部分时候我们定义在元素上的方法都是定义在methods中的
methods将被混入到Vue实例中,可以直接通过vm实例访问这些方法,或者在指令表达式中使用
方法中的this自动绑定为vue的实例,也就是我们需要注意一点,在使用methods时不要通过箭头函数来定义methods函数,因为箭头函数会自动绑定父级作用域的上下文
在methods中定义的事件,可以通过v-on来定义一个方法来接收
<div @click="get($event)"></div>
new Vue({
methods:{
get(event){
}
}
})
在通过v-on定义的方法来接收事件时可以传入参数,$event是vue封装的事件运动状态
在这段代码中在div标签get($event)中$event是我们传入的实参,methods中传入的event是形参
如果我们在div标签中没有传入参数,那么在methods中传入的是实参
在使用v-on进行事件绑定还可以有以下几种写法
<!-- 行内语法 -->
<button v-on:click="counter+=1"></button>
<!-- 对象语法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<input type="text" :value=value @input="value=$event.target.value">
它实际是一下写法的简写形式(这里是对vue中利用v-model分析时写的)
<body>
<div id="box">
<!--<input type="text" :value=value @input="$event.target.value">-->
<input type="text" @input='change($event)'>
{{value}}
</div>
<script>
new Vue({
data: {
value: ''
},
methods:{
change(e){
this.value=e.target.value
}
}
}).$mount("#box")
</script>
</body>
vue.js为v-on提供了事件修饰符,可以通过.表示的指令来调用修饰符
<!--阻止事件冒泡-->
<a @click.stop="click"></a>
<!--阻止默认事件-->
<form @submit.prevent="click"></form>
<!--添加事件侦听器时使用事件捕获模式-->
<a @click.capture="click"></a>
<!--只当事件在元素本身触发时触发回调,例如在子元素触发是不响应的-->
<a @click.self="click"></a>
<!--点击事件只会触发一次-->
<a @click.once="click"></a>
<!--2.3.0版本提供了.passive选项,用来优化scroll等事件的滚动流畅度,提升移动端的流畅度-->
<div @scroll.passive="onScroll"></div>
<!--注意不要及那个passive和prevent同时使用,prevent将会被忽略-->
<!--使用修饰符时注意 1.修饰符是可以串联的-->
<a @click.stop.prevent="click"></a>
<!--2.顺序很重要 @click.prevent.self会阻止所有的点击,而@click.self.prevent只会阻止该元素的点击-->
vue.js提供了键值修饰符,在监听键盘事件时,我们经常需要监测常见键值
<!--只有在按下keyCode键码为13的键时才会触发submit事件-->
<input @keyup.13="submit">
<!--veu为常见的按键提供了别名-->
.enter .tab .delete (捕获 “删除” 和 “退格” 键) .esc .space .up .down .left .right
<!--可以通过全局config.keyCode对象自定义键值修饰符别名,例如定义keyCode为112的按键定义别名为.f1-->
Vue.config.keyCode.f1=112
<!--可以用如下修饰符开启键盘事件监听-->
.ctrl .alt .shift .meta
<!--Alt + C-->
<input @keyup.alt.67="clear">
<!--2.5.0新增加了.exact修饰符,允许我们控制精确的按键-->
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
vue.js提供了鼠标按钮修饰符
.left .right .middle
在一个组件被销毁时所有挂载在该组件上的方法都会被销毁
watch
vue中提供watch对象,可以用来监视实例属性的变化,键是需要观察的表达式,值是对应回调函数/方法名/包含选项的对象,
new Vue({
data: {
a: 1
},
methods:{
click(){
this.a=2
}
},
watch: {
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
}
}
//watch用来监视变量a的变化,在a发生变化后执行我们定义的函数
//函数中传入的两个参数val代表a改变后的值,oldVal代表a改变之前的值
}).$mount(".test")
//也可以通过调用一个在methods中已经定义方法的方法名来执行改动后的操作
new Vue({
data: {
a: 1,
b:{
num:10
}
},
methods: {
click() {
this.a = 2
},
someMethod(n, o) {
console.log(n);
},
},
watch: {
a: "someMethod",
//对于复杂类型的数据,要使用以下的深度类型的方法
b: {
handler(val, old) {
console.log(val);
console.log(old);
}
//如果想要查看对象内部的某个属性值的变化,需要开启深度检测,被监测者需要是一个字符串格式例如 "b.num" 的格式
//如果不开启深度检测对象的两个参数返回的都是改变后的值,如果开启了深度检测那么还是会返回改变之前和改变之后的值
deep:true
}
}
}).$mount(".test")
Vue实例可以通过调用$watch方法来进行监测
var vm = new Vue({
data: {
a: 8
}
methods: {
click() {
this.a = 2
},
someMethod(n, o) {
console.log(n);
},
}
}).$mount(".test")
vm.$watch("a",function (n,o) {
console.log(n);
})
parent
指定已创建的实例的父实例,在两者之间建立父子关系,子实例可以用this.$parent访问父实例
子实例被推入父实例的$children数组中
<body>
<div id="parent"></div>
<div id="child"></div>
<script>
var vm = new Vue({
el: "#parent",
})
var vn=new Vue({
el:"#child",
parent:vm
})
console.log(vn.$parent.$el) //<div id="parent"></div>
console.log(vm.$children[0].$el); //<div id="child"></div>
</script>
</body>
mixins
混合对象可以包含任意组件选项,以组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项
这是vue官方对混合的解释,比较抽象,在实际运用后自己大概有个了解,可以简单理解为混合的作用就是将我们在页面内的组件或实例中的公共部分抽离出来,将这些公共部分单独设置为一个模块,在使用时将该模块导入即可,而不需要重复再去写这些公共部分,
在这一部分上我们可以将它理解为组件,但是与组件的不同在于,混合对象在被导入到实例/组件的时候会自动的查看是否与组件本身已有的数据冲突,如果有冲突,那么它会按照自定的规则进行合并
<body>
<div id="box">
<child></child>
<p @click="click">{{msg}}</p>
</div>
<script>
var msg = {
data: {
msg: "实例混合对象的数据"
}
},
tem = {
data() {
return {
msg: "组件混合对象的数据"
}
}
},
callback = {
methods: {
click() {
console.log("混合对象的点击事件")
}
},
mounted(){
console.log("混合对象的挂载完成函数触发");
}
};
Vue.component("child", {
template: `
<div>
<p @click="click">{{msg}}</p>
</div>
`,
methods: {
click(){
console.log("组件本身的点击事件")
}
},
mixins: [tem, callback]
})
new Vue({
el: "#box",
data: {
msg: "实例原本的数据"
},
mounted(){
console.log("实例本身的挂载完成函数触发");
},
mixins: [msg, callback]
})
</script>
</body>
在上面的栗子我们可以注意到,混合本身的混合规则:
- 如果实例/组件的值为对象的选项,如methods,components将被混合为一个对象,在两个对象键名冲突时,取组件/实例对象的键值对,实例中不存在相同键名时则会将混合对象的键值添加到实例/组件中
- 如果实例/组件和混合对象含有同名选项时,例如存在同名钩子函数,那么会将这些函数混合为一个数组,因此混合对象的钩子函数和实例/组件的钩子函数都将会被调用,但是混合对象的钩子函数将会在实例/组件的钩子函数之前被调用
也可以注册全局混合对象,但是需要注意,一旦使用全局混合对象,将会影响到所有之后所有创建的Vue实例,包括第三方模板,大多数情况下不推荐使用
Vue.mixin({
....
})
filter
在Vue2.0之后,官方取消了内置的过滤器,但是仍然保留了自定义过滤器的方法,我们如果需要对一些常见的文本进行格式化,可以自定义一个过滤器
Vue为我们提供了两种自定义过滤器的方法,第一种是在组件内部自定义一个内部使用的过滤器
<p>{{ str | upperCase}}</p>
new Vue({
//...
filters:{
upperCase(value){
return value.toUpperCase();
}
}
})
第二种就是可以在Vue实例上创建全局的过滤器
new Vue({
//...
})
Vue.filter("lowerCase",(value)=>{
if(!value) return;
return value.toLowerCase();
})
过滤器可以进行联写
<p>{{ str | upperCase | lowerCase }}</p>
在过滤器中,默认的第一个参数就是我们的就收的变量,除此之外还可以接收其他参数,其他参数的第一个是我们函数中参数的第二个,依次类推
<p>{{ str | upperCase | lowerCase("a","b") }}</p>
过滤器除了可以应用在{{ }},也可以用来处理v-bind:
<div v-bind:id="rawId | formatId"></div>
在创建全局的filter时我们一般会将所有的过滤器放在一个文件下,然后利用Object.keys将所有的过滤器绑定到Vue实例上
import filters from './filters'
Object.keys(filters).forEach(key => Vue.filter(key, filters[key]))