写在开始,由于项目更换,需要用到vue + spring boot,所以这个周末又要突击一把了。其中如果有不对的地方还请指出来,毕竟是初学者。写博客当学习笔记。
vue创建
安装vue脚手架
npm install -g vue-cli
创建项目(学习以下面第一种方式创建项目)
vue init webpack project-name
vue init webpack-simple project-name 简单项目结构
项目初始入口文件
由于vue-cli引入了webpack静态资源打包器。相对的入口文件需要到web.config中寻找。
入口起点(entry point)
指示webpack应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
// build/webpack.base.conf.js
entry: {
app: './src/main.js'
}
html-webapck-plugin插件
可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口
// webpack.dev.conf.js
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
new vue参数
main.js中创建vue实例
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
常用配置
- router:路由配置
- data:函数成员
- methods:对象成员
- template:模板
- el:挂载元素
- 生命周期钩子
- props:属性声明
- computed:计算成员
- watch:监视成员
data
data: Vue 实例的数据对象。Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对):浏览器 API 创建的原生对象,原型上的属性会被忽略。大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象。
Vue实例化后添加(或删除)一个属性(例如在方法或生命周期钩子中),Vue是不知道它的。举例如下。
created: function () {
this.$data.testProperty = 'rod chen'
}
created生命周期钩子中添加一个testProperty,但是项目会报错,识别不到当前属性。
模板语法
插值
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:
<h2>插值文本</h2>
{{msg}}
通过使用v-once指令实现一次性插值:
<input v-model="firstName" placeholder="edit me">
<p v-once>Message is: {{ firstName }}</p>
<p>Message is: {{ firstName }}</p>
原始 HTML
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令
<h2>原始html</h2>
<div v-html="rawHtml">我是谁,我在那</div>
//data属性
rawHtml: '<span style="color: red"/>这是插值html</span>'
html属性
Mustache 语法不能作用在 HTML 特性上,遇到这种情况应该使用 v-bind 指令
<h2>html属性</h2>
<div v-bind:id="divId1">设置html属性id</div>
JavaScript表达式
注:只能是表达式,不能是属性。
<h2>js表达式</h2>
{{ number + 1 }}
计算属性和侦听属性
计算属性适用于复杂的逻辑计算。
<h2>计算属性</h2>
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
computed: {
reversedMessage: function () {
return this.message.split(' ').reverse().join(' ')
// return this.message.split(' ').reduceRight(function(x, y) {
// console.log(y);
// return [x].push(y);
// })
}
}
reversedMessage 的值始终取决于 vm.message 的值
计算属性缓存 vs 方法
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值。相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
举例如下:
//通过button点击触发定时器更新message属性。我们可以看到date的数据不依赖于message。但是通过方法的调用,时间会变化,如下图。
<h2>计算属性缓存 vs 方法</h2>
<div id="example">
<p>data date: "{{ dateFromMethod() }}"</p>
<p>计算 date: "{{ date }}"</p>
</div>
methods: {
click (event) {
var self = this
setInterval(function () {
console.log(self)
self.message = self.message + 1
}, 1000)
},
dateFromMethod () {
return (new Date()).toLocaleTimeString();
}
}
computed: {
date: function () {
return '计算结果有javascript表达式计算而来:' + new Date().toLocaleTimeString()
}
}
侦听属性
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
<h2>侦听属性</h2>
<div id="example">
<input v-model="firstName" placeholder="edit me">
<p v-once>Message is: {{ firstName }}</p>
<p>Message is: {{ firstName }}</p>
<p>Message is: {{ fullName }}</p>
<p>Message is: {{ fullNameTest }}</p>
</div>
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
绑定class
传给 v-bind:class 一个对象,以动态地切换 class
<div v-bind:class="{ 'red-font': isActive }">
文字为红色
</div>
使用计算属性
computed: {
classObject: function () {
return {
'red-font': this.isActive
}
}
}
绑定内联样式
<div v-bind:style="{ color: activeColor }">
文字为红色
</div>
样式多重值
从 2.3.0 起你可以为 style 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值。多用于浏览器兼容性。
<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">
样式多重值
</div>
条件渲染
- v-if:条件渲染
- v-else-if: 充当 v-if 的“else-if 块”,可以连续使用
- v-else: 表示 v-if 的“else 块”
条件一旦符合,后面的代码不会执行,就是下面例子中onePage和twoPage都是true的情况,会显示page 1。
v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。
<div v-if="onePage">
Page 1
</div>
<div v-else-if="twoPage">
Page 2
</div>
<div v-else>
Page 3
</div>
用key管理可复用的元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,也可能会带给我们一些不是预期的结果。请看下面的例子:
<div class="hello">
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
<button @click="toggle">toggle login type</button>
</div>
data () {
return {
loginType: 'username'
}
},
methods: {
toggle: function () {
this.loginType = this.loginType === 'username' ? '' : 'username'
}
}
然后看一下效果:
可以看到重新渲染的部分为label和input的placeholder。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder。
但是我们的需求是这两个元素是完全独立的,不要复用它们。只需添加一个具有唯一值的 key 属性即可。
<div class="hello">
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="user-name">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="user-email">
</template>
<button @click="toggle">toggle login type</button>
</div>
v-show
根据条件展示元素的选项是 v-show 指令
<h1 v-show="ok">Hello!</h1>
v-if vs v-show
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
*** 不推荐同时使用 v-if 和 v-for。
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
列表渲染
我们用 v-for 指令根据一组数组的选项列表进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名。
<div class="hello">
<ul id="example-1">
<li v-for="(value, index) in items" :key="index">
{{ index + ":" + value.message }}
</li>
</ul>
</div>
在 v-for 块中,我们拥有对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引。最好绑定key值。
***可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法
对象的 v-for
v-for 通过一个对象的属性来迭代。
<div class="hello">
<ul id="example-1">
<li v-for="(value, key, index) of items" :key="key">
{{ key + ':' + value + ':' + index}}
</li>
</ul>
</div>
** 在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。
Object.keys() 获取自有属性中枚举属性的合集字符串。详情
key
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
这句话什么意思呢?请看下面的例子。例子的功能是:对于下面三个选择项,每当我选择一个项目,当前项目就会被删除。
<div class="hello">
<ul id="example-1">
<li v-for="(value, index) of items" v-if="!value.isChecked">
<input type="checkbox" v-on:click="toggleFinish(value)">
{{ index + ":" + value.chose1 }}
</li>
</ul>
</div>
data () {
return {
items: [
{ chose1: 'rodchen', isChecked: false },
{ chose1: 'rod', isChecked: false },
{ chose1: 'rod1', isChecked: false }
]
}
},
methods: {
toggleFinish: function (value) {
value.isChecked = !value.isChecked
this.items = this.items.filter(function(item){
return !item.isChecked;
})
}
}
请看gif中,我第一步在第一个选项添加了一个新的属性property="test",当我点击第一个项目删除之后,会发现属性依然在,并且之前第二个checkbox被选中了。就地复用,当前vue在一个项目还是复用乐乐之前的元素。但是我们不想这种情况出现,所以需要加上key。
但是key不能设置成index,原因相信你懂的。
数组更新检测
Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
注意事项
数组异常情况
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
- 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:vm.items.length = newLength
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
对象异常情况
对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
Vue.set(vm.userProfile, 'age', 27)
多个属性情况下,应该将新属性使用新对象与原对象通过Object.assign构成新的对象。
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})