vue的详解
1、初始化一个vue项目
> cnpm install -g vue-cli # 全局安装vue-cli
> vue -V #检查vue版本
> vue init webpack vue-project #初始化一个vue项目
> cnpm install #进入项目目录 安装需要的依赖
> cnpm run dev #启动项目
> npm config set registry https://registry.npm.taobao.org
> npm config get registry
-
父组件
<Todo
:message="我是父数据传给子组件" #可以通过:message="父传子的数据"
v-for="(item) in groceryList"
v-bind:todo="item" #可以通过v-bind 将数据传给子组件 todo是子组件的props
v-bind:key="item.id"
></Todo>
<script>
import Todo from '@/components/Todo' #引入子组件
export default {
name: 'HelloWorld',
data () {
},
components: {
Todo #组件见
}
}
</script> -
子组件
<template>
<div class="hello">
我是子组件
<li>-
子组件 子组件拥有自己的生命周期
<template>
<div class="hello">
我是子组件
<li @click="emitToparent">点击我传数据给父组件</li>
</div>
</template>
<script>
export default {
name: 'Todo',
methods: {
emitToparent () {
this.$emit('child-event', '我是子组件传数据给父组件') #child-event是父组件绑定标示
}
}
}
</script> -
父组件
<template>
<div class="hello">
<Todo
@child-event="parentEvent"
></Todo>
</div>
</template>
<script>
import Todo from '@/components/Todo'
export default {
name: 'HelloWorld',
data () {
return {
}
},
components: {
Todo
},
methods: {
parentEvent (data) {
console.log('接入数据', data)
}
}
}
</script>- v-if 绑定判断关系 eg:<p v-if="seen">现在你看到我了</p>
- v-bind 绑定html标签属性 eg:<a v-bind:href="url">...</a>
- v-on 绑定on事件 eg:<a v-on:click="doSomething">...</a>
- <a v-bind:[attributeName]="url"> ... </a> 动态绑定参数 data属性需有attributeName 其值为 "href",那么这个绑定将等价于 v-bind:href<input type="text" v-model.lazy="value"> #lazy这个修饰符会在光标离开input框才会更新数据
<input type="text" v-model.trim="value"> #trim是输入框过滤首尾的空格
<input type="text" v-model.number="value"> #number的功能是先输入数字就会限制输入只能是数字
<button @click.stop="test">test</button> #stop是阻止事件冒泡
<a @click.prevent="test">test</a> #prevent 阻止默认行为,相当于调用了event.preventDefault()方法,比如表单的提交、a标签的跳转就是默认事件
<div @click.self="test"></div> #self 只有元素本身触发时才触发方法,就是只有点击元素本身才会触发
<div @click.once="test"></div> #once 只能用一次,无论点击几次,执行一次之后都不会再执行- v-bind 缩写
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
- v-on 缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a><div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})new Vue({
data: {
n: 0,
obj: {
a: "a"
}
},
template: `
<div>
<button @click="n += 1">n+1</button>
<button @click="obj.a += 'hi'">obj.a + 'hi'</button>
<button @click="obj = {a:'a'}">obj = 新对象</button>
</div>
`,
watch: {
n() {
console.log("n 变了");
},
obj:{
handler: function (val, oldVal) {
console.log("obj 变了")
},
deep: true // 该属性设定在任何被侦听的对象的 property 改变时都要执行 handler 的回调,不论其被嵌套多深
},
"obj.a":{
handler: function (val, oldVal) {
console.log("obj.a 变了")
},
immediate: true // 该属性设定该回调将会在侦听开始之后被立即调用
}
}
}).$mount("#app");-
deep 控制是否要看这个对象里面的属性变化
-
immediate 控制是否在第一次渲染是执行这个函数
vm.$watch() 的用法和 watch 回调类似
-
vm.$watch('data属性名', fn, {deep: .., immediate: ..})
vm.$watch("n", function(val, newVal){
console.log("n 变了");
},{deep: true, immediate: true})vue.esm.js?efeb:628 [Vue warn]: Error in callback for watcher "fullName": "TypeError: Cannot read property 'call' of undefined"
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
<my-component v-bind:class="{ active: isActive }"></my-component><h1 v-show="ok">Hello!</h1>
<ul id="example-1">
<li v-for="(item,i) in items" :key="i"> #其中in可以使用of代替
{{ item.message }}
</li>
</ul><div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div><li v-for="n in even(numbers)">{{ n }}</li>
<div id="example-2">
<!-- `greet` 是在下面定义的方法名 -->
<button v-on:click="greet">Greet</button> #也可以传递数据 v-on:click="greet('abc',$event)"
</div>
methods: {
greet: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert('Hello ' + this.name + '!')
// `event` 是原生 DOM 事件
if (event) {
alert(event.target.tagName) #得到原生事件
}
}
}computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}<input v-on:keyup.enter="submit"> #按键修饰符
<input v-on:keyup.13="submit"> #按键码
<input v-on:keyup.k="submit" #k键<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p><!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" >
输入值转为数值类型
<input v-model.number="age" type="number">
如果要自动过滤用户输入的首尾空白字符
<input v-model.trim="msg"><h3>{{ title }}</h3>
<div v-html="content"></div> 这样会报错的 # every component must have a single root element
正确 eg:
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div><div :style="{fontSize: postFontSize + 'em'}"></div> #在绑定的样式中要使用大小写
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
v-on:enlarge-text="postFontSize += 1"
></blog-post><input v-model="searchText">
这里雷同于:
<div id="app">
<custom-input :value="searchText" @input="searchText = $event"></custom-input>
</div>
<template>
<div>
<input :value="value" @input="$emit('input', $event.target.value)"/>
</div>
</template>
<script>
export default {
name: 'BlogPost',
props: ['post', 'value'],
data () {
return {
seen: true,
obj: {
content: '这个是子组件'
}
}
}
}
</script>Vue.component('my-component-name', { /* ... */ })
Vue.component('MyComponentName', { /* ... */ })Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b><component-a></component-a></component-b>
<component-c></component-c>
</div>
#笔者经过测试 只能后加载能使用前面加载的 比如在a使用b组件会报错的,应该是顺序加载的原因吧props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}父组件
<base-checkbox :checked="lovingVue" @change="lovingVueFunc" ></base-checkbox> #checked接收是一个bool值的变量,change接收是一个影响lovingVue的方法,
子组件
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})[Vue warn]: Error in v-on handler: "TypeError: handler.apply is not a function
eg:
this.checked = this.checked === false ? true : false; #报错Unnecessary use of boolean literals in conditional expression
应该替代为:
this.checked = !this.cheked12% building modules 22/31 modules 9 active ...pace/vue_demo/Vue-Project/src/App.vue{ parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }.
95% emitting
> 这个是因为 prettier版本有问题导致的 更换版本即可
> 在当前项目中直接cnpm install prettier@~1.12.0 -D 或者cnpm install prettier@~1.12.0 --save-dev 然后重新npm run dev<template>
<div id="example">
<button @click="decrement">-</button>
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
其他组件可以使用:
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
mapGetters 辅助函数
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}// ...
mutations: {
increment (state, n) { #n为increment的第一个参数
state.count += n
}
}
store.commit('increment', 10) #直接调用传入参数import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) { #context则代表是所有的store 但不是store
context.commit('increment')
}
}
})<template>
<div id="app">
Hello app.vue!
<!-- 显示路由组件的位置 -->
<router-view></router-view>
</div>
</template>export default new Router({
// mode: 'history', #默认是使用history模式的 在new VueRouter的时候配置mode值为history来改变路由模式,本质使用H5的histroy.pushState方法来更改url,不会引起刷新 ,直接访问路由是默认是首页,关闭即可
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
}]<div>
<router-link to = "/home">首页</router-link>
</div>// 路由的懒加载方式
{ path :"/home",component:()=>import("../views/Home")},// 当我访问/home首页时,页面才去加载Home组件,减少首页加载的时长
{ path :"/list",component:()=>import("../views/List")}, //也可以使用 component:()=>import('@/views/List')
{ path :"/mine",component:()=>import("../views/Mine")}{ path :"/list",component:()=>import("../views/List"),children:[
// 二级路由前不需要加“/”
{ path: "audio", component: () => import("../views/Audio") },
{ path: "video", component: () => import("../views/Video") }
]}<div>
<router-link to = "/list/audio">音频</router-link>
<router-link to = "/list/video">视频</router-link>
</div>
<router-view></router-view><router-link tag = "li" :to = "{name:'detail',params:{id:'1'},query:{title:'最近播放'}}">我的歌单</router-link>
路由跳转中 路由1,2同个路由节点,路由1设置了replace ,则先点击路由2再到路由1 ,用户点击浏览器退回按钮在路由2会被替换
路由跳转到不同的url默认是push的过程,当用户点击浏览器后退按钮式时,则回到之前url,replace属性可以控制router-link的跳转不被记录。
7、replace
注解:name是要跳转的路由的名字,也可以写path来指定路径,但是用path的时候就不能使用params传参,params是传路由参数,query传queryString参数
router-link的to属性,默认写的是path(路由的路径),可以通过设置一个对象,来匹配更多。
6、to
注:二级路由组件的切换位置依然由router-view来指定(指定在父级路由组件的模板中)。
在创建路由表的时候,可以为每一个路由对象创建children属性,值为数组,在这个里面又可以配置一些路由对象来使用多级路由,注意:一级路由path前加'/',二级路由前不需要加'/'。
5、二级路由:
懒加载也叫延迟加载,即在需要的时候进行加载,随用随载。在单页应用中,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,延时过长,会出现长时间的白屏
4、路由懒加载
3、使用route-link来创建切换路由工具
2、在route中使用的mode是history模式
vue的路由
6、分发action mutation 执行的都是同步,但是action则可以执行异步
5、可以使用mapMutations映射到vue
4、改变store且传入参数
3、mapGetter使用
2、vuex 的getter使用
1、获取多个状态的时候可以使用mapstate处理
vue官方调试工具:https://github.com/vuejs/vue-devtools
Flux文档:https://facebook.github.io/flux/docs/overview
Redux文档:https://redux.js.org/
一些link
vuex的一些基本语法
注:开发项目中遇到的bug处理
37、在eslint中 当存在简单替代方案时,不允许使用三元运算符
36、在vue中函数不能与变量名一致,否则报错
35、checkbox 中替代v-model的写法
34、子组件的prop数据是单向流动的,意味着不能通过子组件去改变父组件的元素
33、在prop的子组件中可以传入动态或者静态的prop
32、prop定义数据的类型
31、在prop中使用大写 在浏览器中可以直接转为小写的
30、组件的全局注册
29、组件名称:短横线或者是驼峰命名
28、在父子组件中使用事件 可以使用v-model 来绑定事件
27、在元素中添加js事件
26、在style中添加变量
25、每个组件都是新的实例,每个实例可以维护一份被返回对象的独立的拷贝,因为每个组件数据互不影响,组件元素比较只有一个根元素、否则报错
组件可与v-model使用
24、修饰符
23、表单输入使用v-model
22、按键修饰符
可以理解为该修饰符的作用就是把一个
此时点击就会弹窗:
添加修饰符:
此时点击页面中的按钮无任何反应。
(7). native:在父组件中给子组件绑定一个原生的事件,就将子组件变成了普通的HTML标签,不加'. native'事件是无法触 发的。
(6). passive:该修饰符大概意思用于对DOM的默认事件进行性能优化,根据官网的例子比如超出最大范围的滚动条滚动的。
(5). once:设置事件只能触发一次,比如按钮的点击等。
此时点击最内层:
(4). self:将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响
点击最内层结果:
多个获取事件 :
此时点击最内层div,结果如下:
(3). capture:捕获冒泡,即有冒泡发生时,有该修饰符的dom元素会先执行,如果有多个,从外到内依次执行,然后再按自然顺序执行触发的事件。
默认事件指对DOM的操作会引起自动执行的动作,比如点击超链接的时候会进行页面的跳转,点击表单提交按钮时会重新加载页面等,使用".prevent"修饰符可以阻止这些事件的发生。 此时点击超链接不会进行页面的跳转。
(2). prevent:阻止默认事件的发生
。
再次点击内层div的结果如下:
修改代码,为内层点击事件添加事件".stop"修饰符:
点击外层div的结果:
点击内层
(1). stop:阻止冒泡(通俗讲就是阻止事件向上级DOM元素传递)
21、修饰符
20、v-on 在事件中获取元素属性
19、v-for中可以使用方法
18、对已有对象赋值多个新属性 使用Object.assign() 、_.extend()
17、v-for 中使用对象
16、v-for 进行循环
15、如果频繁的话使用v-show 如果条件复杂则使用v-if
14、v-show 判断元素是否显示 类似于display
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外
13、用 key 管理可复用的元素
12、html绑定class 可以使用object 、可以使用[]三元表达式、 {}做类似if判断
11、在vue中属性data跟methods方法名称不一样
watch 是可以有setter getter 方法的 笔者使用会报错
-
注意:不应该使用箭头函数来定义 watcher 函数,因为箭头函数没有 this,它的 this 会继承它的父级函数,但是它的父级函数是 window,导致箭头函数的 this 指向 window,而不是 Vue 实例
一个对象,键是 data 对应的数据,值是对应的回调函数。值也可以是方法名,或者包含选项的对象,当 data 的数据发生变化时,就会发生一个回调,他有两个参数,一个 val (修改后的 data 数据),一个 oldVal(原来的 data 数据) Vue 实例将会在实例化时调用
$watch()
,遍历 watch 对象的每一个属性10、watch
9、computed 通过计算出来的属性不需要调用直接可以在 DOM 里使用 页面渲染就会执行的
8、v-缩写
7 、修饰符
6、绑定指令
{{ }} 可以进行简单的运算以及三运表达式 {{ message.split('').reverse().join('') }}
5、插入数据中使用双大括号
-
4、子组件传数据给父组件
-
3、父组件传数据给子组件
2、配置本地的vue的淘宝镜像