1.直接用script引入
2.npm
// 空文件夹中可以直接安装的
npm install vue // 最新稳定版
文件:
\node_modules\vue:
dist,src,types,package.json,readme.md等
3.vue-cli
Vue 提供了一个官方的 CLI,为单页面应用 (SPA) 快速搭建繁杂的脚手架。
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。
eg:插值,属性,结构控制(if,for,),事件,v-model,组件树思想。
创建一个vue实例:
var vm = new Vue({
// 选项
})
数据和方法:
var vm = new Vue({
el: '#example',
data:{
msg:"我是msg",
},
methods:{
}
})
生命周期钩子:
参考基础知识第8项(在下面)
eg:{{msg}}
$el
,$data
,$watch
,$set
等。v-once
和v-html='msg'
mustache // n.胡子;须状物;
英 [mə’stɑ:ʃ];美 [ˈmʌsˌtæʃ, məˈstæʃ]
<div id="app">
{{msg}}
</div>
<script>
var app=new Vue({
el:"#app",
data:{
msg:"我是hello world",
}
})
console.log(app.msg);
</script>
当一个 Vue 实例被创建时,它将 data 对象中的所有的属性加入到 Vue 的响应式系统中。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。
响应式是指:在控制台修改app.msg=“lks”,那么页面也是会自动刷新的。eg:
var data={a:1};
var vm=new Vue({
el:"#app",
data:data,
})
// vm.a===data.a =>true
// 设置属性也会影响到原始数据
vm.a = 2
data.a // => 2
// ……反之亦然
data.a = 3
vm.a // => 3
vm.b=4;
console.log("vm.b:",vm.b); // 4
console.log("data.b:",data.b); // undefined
// 页面上b的值会显示4(现在不会显示了,报错;但是可以打印出来);但是只显示初始化后的值,如果再改变vm.b的值,不会更新视图,已经断开连接了;
值得注意的是只有当实例被创建时 data 中存在的属性才是响应式的。也就是说如果你添加一个新的属性,将不会触发任何视图的更新。
除了数据属性,Vue 实例还暴露了一些有用的实例属性与方法。它们都有前缀 $,以便与用户定义的属性区分开来。
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用,初始化的时候,没有执行的。
})
$watch执行的顺序问题:
vm.a=333;
vm.$watch('a',function(n,o){
console.log(n);
console.log(o);
console.log(this===vm);
})
// $watch是没有执行的;只有vm.a放在$watch后面,那么才会执行;
// 没有使用箭头函数,this指向vm对象
vm.$watch('a',function(n,o){
console.log("新值:",n,"旧值:",o);
console.log("this指向问题:",this===vm); // 返回true
this.test();
})
/* vm.$watch('a',function(n,o){
console.log("新值:",n,"旧值:",o);
console.log("this:",this===vm);
this.test();
})*/
// 使用了箭头函数,this执行window
vm.$watch('a', n => {
console.log("this:",this);
console.log("this===Window:",this===Window); // false
console.log("this===window:",this===window); // true window:Window类型。
console.log("this===this.window:",this===this.window); // true
console.log("this.vm===vm:",this.vm===vm); // true
console.log("this.vm:",this.vm); // 就是vm对象
this.vm.test(); // 执行了
})
扩展:
v-once // 属性
v-html="msg" // 属性,msg没有花括号
v-once的使用:
<span v-once>这个将不会改变: {{ msg }}</span> // 一次性的插值
v-html的使用: => 很容易导致 XSS 攻击
// msg 是 "我是标题
",
<span v-html="msg">我是span标签</span>
msg中的html片段会插入到span中,span中本来的内容被替换掉了(“我是span标签”没有了),效果如下:
<span><h2>我是标题</h2></span>
可以使用js表达式:
{{number+1}}
{{ok?'YES':'NO'}}
<div v-bind:id="'list-'+id"></div>
错误示例:
{{ var a = 1 }}
{{ if (ok) { return message } }}
v-bind:title=“msg”
鼠标悬浮几秒试试 // msg
鼠标悬浮几秒试试 // {msg}
鼠标悬浮几秒试试 // {{msg}},并且会报错,不认识{{}}
鼠标悬浮几秒试试 // 正确,提示:msg的内容
<div v-bind:id="'list-'+id"></div>
<a v-bind:href="url">...a>
<a :href="url">...a>
v-if="seen"
v-if="count>1"
,v-else-if="count>0"
,v-else
v-if 如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 元素(类似angular中ng-container)。
你能看到我吗?
NO!!!
app.seen=true/false;
注:v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
用 key 管理可复用的元素
eg:此时:共享input,只是更换了placeholder而已
以下,由于有key,那么input是没有共享的
// 此时:自己的input值也不会保留了(切换的时候,被清空了)。
v-show:
Hello!
不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。
注意,v-show 不支持 元素,也不支持 v-else。
v-for="item in items"
v-for="item of items" // of也是可以的
加索引:
{{ index }} - {{ item.message }}
使用key:
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
一个对象的 v-for
-
{{ value }}
// js:
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
你也可以提供第二个的参数为键名:
{{ key }}: {{ value }}
第三个参数为索引:
{{ index }}. {{ key }}: {{ value }}
注:vue不能检测以下数组的变动:
1.当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
2.当你修改数组的长度时,例如:vm.items.length = newLength
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
解决第一类问题:
// 方法一:Vue.set
Vue.set(vm.items, indexOfItem, newValue)
vm.$set(vm.items, indexOfItem, newValue)
// 方法二:Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
解决第二类问题:
vm.items.splice(newLength)
注:
1.
this.list[2].title=44444;
这样的设置,还是响应式的。
2.angular的*ngFor
中,不会存在for循环渲染的问题。
由于 JavaScript 的限制,Vue 不能检测对象属性的添加
或删除
:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
对于已经创建的实例,Vue 不允许动态添加根级别
的响应式属性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性。例如
// 会报错的
vm.$set(vm,'b',333);
vm.$set(vm.$data,'b',333);
报错信息如下:
[Vue warn]: Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option.
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
Vue.set(vm.userProfile, 'age', 27) //
// 或者:
vm.$set(vm.userProfile, 'age', 27)
注:属性key,是带引号的,要不然报错,当变量了。
// 这样添加,不是响应式的,页面不会更新
vm.userProfile.age=333;
有时你可能需要为已有对象赋值多个新属性,比如使用 Object.assign() 或 _.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样:
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
你应该这样做(创建一个新对象):
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
类似于 v-if,你也可以利用带有 v-for 的 来循环渲染一段包含多个元素的内容。
todoItem案例:
<div id="app">
<form @submit.prevent='addItem'>
<label>新item</label>
<input type="text" v-model="newItem">
<button>新增</button>
</form>
<ul>
<todo-item v-for="(item,index) in list"
:title="item.title"
:key="item.id"
@remove='removeItem($event,index)'>
</todo-item>
</ul>
</div>
Vue.component('todo-item', {
template: `
{{title}}
`,
props: ['title']
})
var vm = new Vue({
el: '#app',
data: {
newItem:'',
newItemId:5,
list: [
{id: 1, title: "title1111"},
{id: 2, title: "title2222"},
{id: 3, title: "title3333"},
]
},
methods: {
addItem(){
this.list.push({id:this.newItemId++,title:this.newItem})
this.newItem='';
},
removeItem(e,index) {
console.log(e);
console.log("removeItem:",index);
this.list.splice(index,1);
}
}
})
v-on:click=“reverseMsg”
<button @click="reverseMsg">逆转消息</button>
// js
methods:{
reverseMsg:function(){
this.msg=this.msg.split("").reverse().join("");
}
}
<a v-on:click="doSomething">...a>
<a @click="doSomething">...a>
.stop,.prevent,.capture,.self,.once,.passive
// 组织冒泡
<a v-on:click.stop="doThis">a>
// 阻止默认事件(阻止元素发生默认的行为)
<form v-on:submit.prevent="onSubmit">form>
<a v-on:click.stop.prevent="doThat">a>
<form v-on:submit.prevent>form>
<div v-on:click.capture="doThis">...div>
<div v-on:click.self="doThat">...div>
<div id="app">
<div style="width: 100px;height: 100px;border: 1px solid red;" @click.self="onClick">
<button @click="onBtnClick">我是按钮button>
<form @submit.prevent="onSubmit">
<button>提交button>
form>
div>
div>
<script>
var vm= new Vue({
el:"#app",
data:{
},
methods:{
onClick(){
console.log('onClick触发了');
},
onBtnClick(){
console.log('onBtnClick触发了');
},
onSubmit(){
console.log('onSubmit触发了');
}
}
})
script>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
eg:
enter,tab,delete,esc,space,up,down,left,right,page-up,page-down,
其中:up,down,left,right才是上下左右的箭头键。
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
// 不是上下箭头,就是pageUp和pageDown键
<input v-on:keyup.page-down="onPageDown">
<input v-on:keyup.page-up="onPageUp">
.ctrl,.alt,.shift,.meta。
这几个键必须配合其他键才会生效,eg:ctrl+c。
.left,.right,.middle
<input type="text" @mouseup.right="onRight">
v-model=“msg”
双向绑定的事件:@input
,@change
,@keyup.enter
,@blur
;angular中:ngModelChange
。
参考:https://blog.csdn.net/zuoyiran520081/article/details/86611608
.lazy,.number,.trim。
<input v-model.lazy="msg" >
<input v-model.number="age" type="number">
<input v-model.trim="msg">
不要在选项属性或回调上使用箭头函数,eg:
created: () => console.log(this.a)
或
vm.$watch('a', newValue => this.myMethod())
。
// this的指向改变了!指向window,那么使用this.vm.a是不是就可以打印了???不可以。
因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止。
var vm=new Vue({
el:"#app",
data:{
count:0,
},
created(){
console.log('this:',this); // Vue
console.log('this:',this===vm); // false
console.log('this.vm:',this.vm); // undefined
console.log('this.count',this.count); // 0
},
// created:()=>{
// console.log('this:',this); // window:Window
// console.log('this:',this===window); // true
// console.log('this.vm:',this.vm); // undefined
// console.log('vm:',vm); // undefined
// console.log('created',this.vm.count); // 报错了
// }
})
vm.$watch('count',(n,o)=>{
console.log(this); // window:Window
console.log(n,o); // 3 0
console.log('this.vm.count',this.vm.count); // 3
console.log('vm.count',vm.count); // 3
})
vm.count=3;
生命周期函数:create,mount,update,destory
new Vue() // 初始化Vue
beforeCreate,
created,
beforeMount,
mounted,
beforeUpdate,
updated,
beforeDestroy,
destroyed
页面刷新之后,执行:beforeCreate,created,beforeMount,mounted,
修改数据之后,执行:beforeUpdate,updated,
跳转到别的页面,执行:???
<div id="app"></div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
count: 0,
},
methods: {},
updated() {
console.log("updated");
}
})
vm.count=6;
</script>
// 此时,beforeUpdate和updated并不执行!!!!
// 只有html中用了变量,那么才会执行update的钩子函数。
指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
现在你看到我了
一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如,v-bind 指令可以用于响应式地更新 HTML 特性;
在这里 href 是参数,告知 v-bind 指令将该元素的 href 特性与表达式 url 的值绑定
...
计算属性,侦听属性,方法的区别???
eg:
{{ message.split('').reverse().join('') }}
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性。
eg:
// html:
Original message: "{{ message }}"
Computed reversed message: "{{ reversedMessage }}"
// js:
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。
计算属性:会缓存,如果依赖变量不变化,那么返回值不变;
方法:每次都会重新执行。
// html:
Reversed message: "{{ reversedMessage() }}"
// js
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的
。只在相关依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
{{ fullName }}
// js:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
上面代码是命令式且重复的。将它与计算属性的版本进行比较:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
11.class与style绑定:
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
// 1.单个
<div v-bind:class="{active:isActive}">我是div标签div>
// 2.多个:class名字,可以加引号,也可以不加。
<div v-bind:class="{active:isActive,'text-danger':hasError}">我是div标签div>
// 3. 对象
<div v-bind:class="classObj">我是div标签div>
此时对应的js为:
data: {
classObj:{
active:true,
'text-danger':true
}
}
其中:data中不可以使用data的属性的,eg:
data: {
isRed: true,
isBlue: true,
isWeight: true,
isFz: true,
classObj2: {
'red': this.isRed, // 不可以使用this
fw9: this.isWeight,
fz14: is.isFz,
},
},
可以使用计算属性
1.数组:
直接写:
我是正文
或者:
// js:
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
渲染为:
2.三元:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
当在一个自定义组件上使用 class 属性时,这些类将被添加到该组件的根元素上面。这个元素上已经存在的类不会被覆盖。
eg:
// html
// js:
Vue.component('my-component', {
template: ' '
})
HTML 将被渲染为:
data: {
activeColor: 'red',
fontSize: 30
}
直接绑定到一个样式对象通常更好,这会让模板更清晰:
data: {
styleObject: {
color: 'red',
fontSize: '14px'
}
}
v-bind:style
的数组语法可以将多个样式对象应用到同一个元素上:
// html:
我是style数组的样式
// js:
data:{
style1:{
color:'red'
},
style2:{
fontSize:'20px',
}
},