VUE.js
v-bind/v-on/v-model
v-bind
v-bind主要用于属性绑定,v-bind:属性名可以简写为:属性名。单向绑定。
单值绑定
<div id="dome"> <!-- 使用大括号"{{vclass}}"无法渲染属性 --> <p class="{{vclass}}">{{vdata}}</p> <!-- 使用v-bind:进行绑定后,即可渲染无需添加大括号 --> <p v-bind:class="vclass">{{vdata}}</p> <!-- : 是 v-bind: 的简写 --> <p :class="vclass">{{vdata}}</p> </div>
<script>
// new Vue({}) 简写-> vnew
new Vue({
el: "#dome",
data:{
vdata: "我修改了字体颜色",
vclass: "color"
}
})
</script>
多值绑定
<div id="dome">
<!-- 使用数组形式进行多值绑定 -->
<p :class="[vcolor, vbc]">{{vdata}}</p>
<!-- 多值在Vue的data属性中已经进行绑定 -->
<p :class="vclass">{{vdata}}</p>
<!-- 根据真假渲染 -->
<p :class="{color:class1, backcolor:class2}">{{vdata}}</p>
</div>
<script>
// new Vue({}) 简写-> vnew
new Vue({
el: "#dome",
data:{
vdata: "我修改了字体颜色",
vcolor: "color",
vbc: "backcolor",
vclass: 'color backcolor',
class1: false,
class2: true
}
})
</script>
style绑定
直接使用style配置样式时进行属性绑定,可能会碰到一个属性名不符合规范的报错问题,一些样式属性的名称会出现中横线,在个别主流编程语言的变量名中均不支持中横线所以就会导致报错。如何解决这种报错,其实也很简单,主要方法有两种,
- 给不合法的变量名加上引号,在vue的data属性中,键名加不加引号效果都一样,如果你想可以把所有键名都加上引号。比如:
'font-size': '30px'
- ==将不合法变量名改为驼峰命名模式,==vue会自动将驼峰命名的变量名转换为我们需要的变量名,比如:
fontSize: '25px'
除此之外,style还可能遇到绑定后无法生效的问题,这里必须要加上大括号才能生效。
<div id="dome">
<p :style="pclass1">{{vdata}}</p>
<p v-bind:style="pclass2">{{vdata}}</p>
<p>{{vdata}}</p>
<!-- 这里我踩过的坑大家可以注意一下 -->
<!-- style属性绑定时候需要加上一个大括号{} -->
<!-- style属性原本比如我想要一个红色字体可以直接写成style="color:red" -->
<!-- 这时如果你想把red换成一个Vue中的数据,直接进行绑定:style="color:Vue元素"会导致页面所以显示都消失,且不会有任何报错,如下 -->
<!-- <p :style="color:vblue">我是蓝色字体</p> -->
<!-- 正确的写法应该需要给属性的值添加上一个大括号绑定才能生效:style="{color:Vue元素}" -->
<p :style="{color:vred}">我是红色字体</p>
</div>
v-model
v-model默认绑定input的value,也是属性绑定,但是是双向绑定,v-bind的绑定只是单向的,他会将data中的数据投影到绑定的地方,在被绑定的地方对数据修改时,data中的原始数据是不会改变的,而v-model的绑定是双向的,不仅将data中的数据对标签内进行绑定,还会将标签中的数据反向绑定到data中,标签数据改变后data中的数据也会同步改变。
本质上双向绑定v-model
是v-bind
以及v-on
配合使用的语法糖(指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用)。
<input type="text" v-model="vmodel">
的作用就相当于<input type="text" :value="vbind" @input="vbind=$event.target.value">
当前我使用的是文本输入,v-model
会绑定value
属性和input
事件,但绑定其他的如单选、多选、下拉菜单等不同的标签,绑定的属性和事件也不同。
元素绑定
v-model
在内部为不同的输入元素使用不同的属性并抛出不同的事件:
input
标签text
(文本框)与textarea
标签(文本域)时绑定value
属性,使用input
事件(每次输入都会触发事件)input
标签的radio
(单选框)与checkbox
(多选框,多选框绑定的值必须是一个数组)时绑定checked
属性,使用change
(每次改变选择都会触发事件)select
标签(下拉菜单)比较特殊,绑定值虽然在select标签中执行,但最终获取值却是获取的option
标签中的值,默认优先获取标签中value
属性中的值,如果标签中没有value
属性则会获取标签中的元素。
<div id="dome">
<!-- 文本框 -->
文本框:<input type="text" v-model:value='vtext' placeholder="我是文本框, 请输入..."><br>
<!-- 文本域 -->
文本域:<textarea v-model:value='vtextarea' placeholder="我是文本域,请输入..." cols="30" rows="3"></textarea><br>
<!-- 单选框 -->
单选框:
<input type="radio" v-model:checked='vradio' value="男"><label>男</label>
<input type="radio" v-model:checked='vradio' value="女"><label>女</label>
<input type="radio" v-model:checked='vradio' value="中性"><label>中性</label><br>
<!-- 多选框 -->
多选框:
<input type="checkbox" v-model:checked='vchoice' value="真香定理"><label>真香</label>
<input type="checkbox" v-model:checked='vchoice' value="人类本质"><label>复读机</label>
<input type="checkbox" v-model:checked='vchoice' value="咯咯咯"><label>今晚一定</label><br>
<!-- 下拉菜单 -->
下拉菜单:
<select v-model:value="vselect">
<option value="1">A</option>
<option>B</option>
</select>
<!-- 数据 -->
<p>文本框:{{vtext}}</p>
<p>文本域:{{vtextarea}}</p>
<p>单选框:{{vradio}}</p>
<!-- 三元表达式,.length方法用于查看数组长度,可以用于判断是否为空,为空则输出空字符串 -->
<p>多选框:{{vchoice.length==0?'':vchoice}}</p>
<p>下拉菜单:{{vselect}}</p>
</div>
修饰符
v-model有几个修饰符非常好用,这里推荐给大家
- .lazy:一种非同步修改,默认情况下,我们将文本框双向绑定后,我们的任何改变都会被立即同步进入数据,但这种同步在大多数时候是没有必要的,我们可以等待用户全部输入结束后在进行同步,可以节省资源。
- .number:可以看成强制类型转换,将用户输入的内容强制转换成为数字。
- .trim:去除空格(去除文本开头和结尾的所有空格,文本中间如果出现空格则不会去除)
<div id ="app">
<!-- 非同步更新 -->
<input type="text" v-model.lazy='lazy'>
<!-- 如果不用简写,方法必须加在属性value之后才能生效,如果直接写在v-model之后像下方一样是无效的 -->
<input type="text" v-model.lazy:value='lazy'>
<p>非同步更新: {{lazy}}</p>
<!-- 数值转换 -->
未转换: <input type="text" v-model='number'>
已转换: <input type="text" v-model.number='number'>
<p>(未转换时为字符型,为两字符相加,转换后为数值,为数值相加)</p>
<p>{{number}}+{{number}}={{number+number}}</p>
<!-- 去空格 -->
未去空格版: <input type="text" v-model='trim'>
已去空格版: <input type="text" v-model.trim='trim'>
<p>'{{trim}}'</p>
</div>
v-on
v-on主要用于绑定事件,v-on:事件名可以简写为@事件名。事件绑定我们可以看成在HTML页面中触发一个事件(这里的事件可以理解为一个函数)。经过v-on
绑定的属性可以直接执行js代码,也可以去vue中methods中寻找函数执行。
<div id ="app">
<!-- 'v-on==@' 直接执行js代码 -->
<button v-on:click='count-=1'>每次点击-1</button>
<!-- '@是v-on的简写' methods中寻找add函数执行 -->
<button @click='add(10)'>每次点击+10</button>
<p>当前数值为:{{count}}</p>
</div>
如果在事件处理函数中,想要获取原生的DOM
事件,那么在html代码中,调用的时候,可以传递一个$event
参数。
<div id ="app">
<!-- 'v-on==@' 直接执行js代码 -->
<button v-on:click='count-=1'>每次点击-1</button>
<!-- '@是v-on的简写' methods中寻找add函数执行 -->
<button @click='add(10,$event)'>每次点击+10</button>
<p>当前数值为:{{count}}</p>
</div>
script>
//创建Vue实例
var vm = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
add(num){
this.count += num
console.log(event)
}
}
});
</script>
即输出原生的console.log.(event)。
自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件。
事件接口:
- 使用
$on(eventName)
监听事件(父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件) - 使用
$emit(eventName)
触发事件
如果想在某个组件的根元素上监听一个原生事件。可以使用 v-on 的修饰符 .native 。通俗点讲,在父组件中给子组件绑定一个原生的事件,就将子组件变成了普通的HTML标签,不加’. native’事件是无法触发的。
<!--html代码-->
<div id="app">
<my-component v-on:click.native="clickFun"></my-component>
</div>
<!--JavaScript代码-->
Vue.component('my-component', {
template: `<a href='#'>click me</a>`
})
new Vue({
el: '#app',
methods: {
clickFun: function(){
console.log("message: success")
}
}
})
子组件的data最好是一个函数,好处是每个实例可以维护一份被返回对象的独立的拷贝,如果 data 是一个对象则会影响到其他实例(其他引用该子组件的实例)。
使用v-model
组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。
<input v-model="parentData">
等价于:
<input
:value="parentData"
@input="parentData = $event.target.value"
>
以下实例自定义组件 runoob-input,父组件的 num 的初始值是 100,更改子组件的值能实时更新父组件的 num:
<div id="app">
<runoob-input v-model="num"></runoob-input>
<p>输入的数字为:{{num}}</p>
</div>
<script>
Vue.component('runoob-input', {
template: `
<p>
<!-- 包含了名为 input 的事件 -->
<input
ref="input"
:value="value"
@input="$emit('input', $event.target.value)">
</input>
</p>
`,
props: ['value'], // 名为 value 的 prop
})
new Vue({
el: '#app',
data: {
num: 100,
}
})
</script>
由于 v-model 默认传的是 value,不是 checked,所以对于对于复选框或者单选框的组件时,我们需要使用 model 选项,model 选项可以指定当前的事件类型和传入的 props。
<div id="app">
<base-checkbox v-model="lovingVue"></base-checkbox>
<div v-show="lovingVue">
如果选择框打勾我就会显示。
</div>
</div>
<script>
// 注册
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change' // onchange 事件
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
// 创建根实例
new Vue({
el: '#app',
data: {
lovingVue: true
}
})
自定义指令
除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。下面我们注册一个全局指令 v-focus, 该指令的功能是在页面加载时,元素获得焦点:
<div id="app">
<p>页面载入时,input 元素自动获取焦点:</p>
<input v-focus>
</div>
<script>
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
// 创建根实例
new Vue({
el: '#app'
})
</script>
也可以在实例使用 directives 选项来注册局部指令,这样指令只能在这个实例中使用:
<script>
// 创建根实例
new Vue({
el: '#app',
directives: {
// 注册一个局部的自定义指令 v-focus
focus: {
// 指令的定义
inserted: function (el) {
// 聚焦元素
el.focus()
}
}
}
})
</script>
钩子函数
指令定义函数提供了几个钩子函数(可选):
bind
: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。inserted
: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。update
: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。componentUpdated
: 被绑定元素所在模板完成一次更新周期时调用。unbind
: 只调用一次, 指令与元素解绑时调用。
钩子函数的参数有:
-
el: 指令所绑定的元素,可以用来直接操作 DOM 。
-
-
binding
- 一个对象,包含以下属性:
- name: 指令名,不包括
v-
前缀。 - value: 指令的绑定值, 例如:
v-my-directive="1 + 1"
, value 的值是2
。 - oldValue: 指令绑定的前一个值,仅在
update
和componentUpdated
钩子中可用。无论值是否改变都可用。 - expression: 绑定值的表达式或变量名。 例如
v-my-directive="1 + 1"
, expression 的值是"1 + 1"
。 - arg: 传给指令的参数。例如
v-my-directive:foo
, arg 的值是"foo"
。 - modifiers: 一个包含修饰符的对象。 例如:
v-my-directive.foo.bar
, 修饰符对象 modifiers 的值是{ foo: true, bar: true }
。
-
vnode: Vue 编译生成的虚拟节点。
-
oldVnode: 上一个虚拟节点,仅在
update
和componentUpdated
钩子中可用。
<div id="app" v-runoob:hello.a.b="message">
</div>
<script>
Vue.directive('runoob', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})
new Vue({
el: '#app',
data: {
message: '菜鸟教程!'
}
})
</script>
有时候不需要其他钩子函数,可以简写函数:
Vue.directive('runoob', function (el, binding) {
// 设置指令的背景颜色
el.style.backgroundColor = binding.value.color
})
指令函数可接受所有合法的 JavaScript 表达式,以下实例传入了 JavaScript 对象:
<div id="app">
<div v-runoob="{ color: 'green', text: '菜鸟教程!' }"></div>
</div>
<script>
Vue.directive('runoob', function (el, binding) {
// 简写方式设置文本及背景颜色
el.innerHTML = binding.value.text
el.style.backgroundColor = binding.value.color
})
new Vue({
el: '#app'
})
</script>