安装
需安装node、webpack、vue-cli
。
检查node
的安装情况,node -v
。
检查npm
的安装情况,npm -v
。
windows
下更新node
找了很多资料,最后看到说是覆盖安装msi
文件(不太懂这个和重新安装有什么区别)。
安装webpack4
和之前的版本不太一样,先是npm install webpack -g
。如果是自己配置,还需要安装npm install webpack-cli -g
,(好像可以不用安装webpack
,安装vue-cli
时自带,没试过)。
然后安装npm install vue-cli -g
,这里查看版本是vue -V
(V
大写)。
cnpm
替换npm
npm 服务器是放在国外的,有时候会很慢,国内可以使用淘宝镜像 cnpm。
安装淘宝镜像,npm install -g cnpm --registry=http://registry.npm.taobao.org
,验证是否安装成功,cnpm -v
。
还可以修改npm
的指向地址,npm config set registry https://registry.npm.taobao.org
npm install
报错,解决办法:
有的时候我们git
他人的项目,但是执行下载所有依赖npm install
后启动npm run dev
运行的最后一步经常会报错,不是缺少依赖模板,就是node_modules
版本与本机安装的node
和npm
版本不一致。这时解决的方法就是直接删除vue
项目中的node_modules
,同时修改package.json
文件里面的node
和npm
版本号,同电脑一致,然后执行npm install
重新下载所有依赖,最后执行npm run dev
就能成功运行项目了。
删除node_modules
文件:
npm install rimraf -g
rimraf node_modules
搭建项目
vue init webpack projectname
创建项目cd projectname
进入项目文件夹npm install
安装项目依赖,这个命令可以执行是由于,定位到工程文件的前提下,目录下有一个package.json
文件,里面配置了依赖所需;- 安装
vue
路由模块vue-router
和网络请求模块vue-resource
,npm install vue-router vue-resource --save
。
搭建完成之后会产生一个文件夹,如下:
config
是构建配置目录,里面的index.js
第17
行代码可以设置端口port
,我们的8080
端口可能占用,可以在这修改。- 上图中的
index.html
就是入口页面,也可以叫容器,里面有个id
为app
的div
。 src
就是我们写代码的地方,源代码目录。src
中的main.js
就是入口 js 文件,也叫逻辑入口;src
中的App.vue
相当于是主组件,所有的组件都将在它里面组合。这里有个有趣的地方,它里面也有个i
为app
的div
。但却不会和index.html
里的同id
的div
冲突。main.js
会调用主组件App.vue
和路由,并创建一个Vue
实例,关联到index.html
里的div
上,最个div
被替换成App.vue
的div
替换。至于如何替换的,就不太清楚了。
安装各种依赖
npm install xxx xxx --save -dev
--save
是指我们在生产环境下安装的各种依赖,在package.json
中就是dependencies
。-dev
是开发环境下的依赖,在package.json
中就是devDependencies
。
npm 安装package.json
中的模块依赖分为两种情况:package.json
不存在时: 命令:npm init
可自动创建package.json
文件。package.json
存在时: 直接命令:npm install
或者npm install –save-dev
会自动将package.json
中的模块安装到node-modules
文件夹下。
指令
指令 | 描述 |
---|---|
v-once |
数据不更新,初次数据就是永久数据 |
v-if |
判断是否渲染元素,元素在显示和销毁之间切换,适用于不经常改变的场景 |
v-show |
判断是否展示元素,元素在显示和隐藏之间切换 |
v-else v-else-if |
必须和v-if 结合使用,并且语句必须前后连在一起 |
v-for |
优先级比v-if 高,(item,index) in arr/str/num |
v-text / v-html |
|
v-bind |
动态绑定属性、样式、类等,简写直接: |
v-on |
绑定事件,简写@ ,停止冒泡@click.stop= ,阻止默认事件@click.prevent= ,串联写法@click.stop.prevent = |
Class 与 Style 绑定
当有多个条件class
时这样写有些繁琐。所以在数组语法中也可以使用对象语法。
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
条件渲染
v-if
元素必须紧跟在带v-if
或者v-else-if
的元素的后面,否则它将不会被识别。
Vue
为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的key
属性即可。
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS
进行切换。
一般来说,v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好。
当它们处于同一节点,v-for
的优先级比v-if
更高,这意味着v-if
将分别重复运行于每个v-for
循环中。
事件处理
有时候,你可能想在某个组件的根元素上监听一个原生事件。可以使用v-on
的修饰符.native
。
<!-- 阻止单击事件继续传播 -->
<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>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->
<input v-on:keyup.13="submit">
<my-component v-on:click.native="doSomeThing"></my-component>
键盘事件及修饰符
@click.once = " "
, 只有第一次点击有效。@keyup.enter = " "
, 输入完成并且按下回车,才会触发。@keyup.alt.enter = " "
, 输入完成并且同时按下回车和alt
键,才会触发。
实例对象的数据选项
data
data
是Vue
实例的数据对象。Vue
将会递归将data
的属性转换为getter/setter
,从而让data
属性能响应数据变化。
[注意]不应该对data
属性使用箭头函数。
Vue
实例创建之后,可以通过vm.$data
访问原始数据对象。
Vue
实例也代理了data
对象上所有的属性。但是,以_
或$
开头的属性不会被Vue
实例代理,因为它们可能和Vue
内置的属性或方法冲突。可以使用例如vm.$data._property
的方式访问这些属性。
构造Vue
实例时传入的各种选项大多数都可以在组件里使用。只有一个例外:data
必须是函数。
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
}
})
computed
计算属性computed
,实时触发,默认只有getter
方法,有需要时可以加setter
方法。计算结果会缓存,下次直接调用缓存,计算属性只有在它的相关依赖发生改变时(虚拟DOM
和真实DOM
不同时)才会重新求值,是同步的,需要return
出来。
method
对于最终的结果,computed
和method
两种方式是相同的。
然而,不同的是computed
是基于它们的依赖进行缓存的,computed
只有在它的相关依赖发生改变时才会重新求值。这就意味着只要data
还没有发生改变,多次访问computed
会立即返回之前的计算结果,而不必再次执行函数。
相比而言,只要发生重新渲染method
调用总会重新执行该函数。
如果不希望有缓存,则用method
替代。
watch
Vue
提供了一种通用的方式来观察和响应Vue
实例上的数据变动:watch
属性。watch
属性是一个对象,键是需要观察的表达式,值是对应回调函数,回调函数得到的参数为新值和旧值。值也可以是方法名,或者包含选项的对象。Vue
实例将会在实例化时调用$watch
,遍历watch
对象的每一个属性。
除了使用数据选项中的watch
方法以外,还可以使用实例对象的$watch
方法, 该方法的返回值是一个取消观察函数,用来停止触发回调。
当数据需要随着其它数据变动而变动时,我们应该避免滥用watch
属性,使用computed
计算属性也可达到相同的目的。
组件
组件分为全局组件和局部组件,全局组件在所有实例中都可使用,局部组件仅可在注册的实例中使用
组件的创建和使用分为三步:创建组件构造器、注册组件、挂载作用域下实例化
创建构造器
let Profile = Vue.extend({
templete:~
<div> </div>
~
})
注册全局组件
//Vue.component("组件自定义名称","构造器名称")
Vue.component("my-div","Profile");
实例化调用
组件的创建和使用可简化在一起,创建构造器和注册组件可写到一起,
Vue.component("my-div",{
templete:~
<div> </div>
~
})
template 和 script 写模板
用template
写模板,可以像标签一样更直观,用id
来和组件对应
<template id="my-template-div">
<div> </div>
</template>
注册组件时把id
对应
Vue.component("my-div",{
template:"#my-template-div"
})
也可以用script
写模板,需要指定类型,注册时一样的用id
对应,
<script type="text/template" id="my-tempalte-div">
<div></div>
</script>
项目中用template
更多,更直观
组件中的 data 属性,必须是函数
Vue.component("my-parent",{
//组件中data属性,必须是函数的形式传递的
data(){
return{
}
}
template:"#parent"
})
组件通信
子组件获取父组件
通过props
传递,在子组件实例时使用props
数组,显式的声明需要的参数(字符串形式);在子组件调用的时候,通过动态绑定的形式获得数据。组件中可以传值,也可以传引用,还可以传父组件。传值之后,当值更改,其他的相同的不会变更,但传引用会同时变更。
还可以在子组件中通过this.$parent.属性/方法
父组件获取子组件
原始的方式通过自定义事件$on()
监听和$emit()
触发来传递数据;在子组件调用的时候@total=''
监听,在子组件的对应参数变化时使用this.$emit('total')
触发。$emit
(向父组件传递的事件名,向父组件传递的数据)
还可以在父组件中调用子组件的时候,通过ref
属性绑定,然后,this.$refs.xxx.属性/方法
非父子组件传值
新建一个公共的Vue
实例publicVue
,用它传值。在传送方引入这个公共实例,通过publicVue.$emit("名称","数据")
发送。在接收方也映入这个公共实例,通过publicVue.$on("名称",function(data){})
接收。
<div id="#app">
<my-parent :message="message"></my-parent>
</div>
//子组件模板
<template id="child">
<div> {{message}} </div>
</template>
//父组件模板
<template id="parent">
<div>
<my-chilid :message="message"> </my-chilid>
</div>
</template>
<script>
//子组件的实例
let Child = Vue.extend(
template:"#child",
//在子组件实例时使用 props 显式的声明需要的参数(字符串形式)
//第一种写法
//props:["message"]
//第二种写法,比第一种更严谨
props:{
message:{
type:String,
required:true
}
}
);
//注册父组件
Vue.component("my-parent",{
//父组件也要向外层拿数据
props:["message"],
//子组件注册
components:{
"my-chilid":Child
},
template:"#parent"
})
new Vue({
el:"#app",
data:{
message:"今天天气很好!"
}
})
</script>
slot的介绍
slot
分为匿名插槽和实名插槽,匿名插槽可以填入任何标签,实名插槽则必须有对应的slot
属性的标签,标签的slot
的属性值和slot
的name
属性值对应
<div id="app">
<my_slot>
<div slot="cpu"></div>
<div slot="memory"></div>
<div slot="hard-drive"></div>
</my_slot>
</div>
//组件模板
<template id="my_slot">
<div>
//匿名插槽
<slot> 可以替换任何标签 ,默认显示提示的内容</slot>
//实名插槽
<slot name="cpu"> </slot>
<slot name="memory"> </slot>
<slot name="hard-drive"> </slot>
</div>
</template>
<script>
Vue.component("my-slot",{
template:"#my_slot"
})
</script>
路由
安装 vue-router
npm install vue-router --save-dev
<div id="app">
<div>
//6.路由入口
<router-link to="/html5"> html5学院 </router-link>
</div>
<div>
//7.路由出口
<router-view></router-view>
</div>
</div>
<template id="html5">
<div> 学习html5 </div>
</template>
<script>
//1.引入vue-router
import VueRouter from "vue-router"
//2.用 vue-router
Vue.use(VueRouter );
//3.创建组件
let Html5 = Vue.extend({
template:"#html5"
})
//4.配置路由
const router = new VueRouter({
routes:[
{path:"/html5",component:"Html5"},
//记得配置根路由(用 redirect 重新指向)
{path:"/" ,redirect:"/html5"}
],
//删除路径中的 /#
mode:"history"
});
//5.创建 Vue 实例并挂载
new Vue({
router
}).$mount("#app");
</script>
多层路由
//9.配置子路由入口和出口,用 name 代替路径的新入口
<router-link :to="{name:'html5'}"> html5学院 </router-link>
<script>
//7.创建子组件
//8.定义子路由
const routes = [
//定义根路由
{path:"/",redirect:"/html5"},
{
path:"/html5",
//入口的路径太长,可以用 name 属性代替
name:"html5",
component:Html5",
children:[
{path:"child1",component:Child1"},
//定义根路由
{path:"/",redirect:"child1"}
]
}
];
</script>
页面传参
用name
可以传参,组件中用$route.name
接收;
还可以用<router-link>
标签中的to
属性进行传参,使用时:to={name:'xxx',params:{username:'xxx',id:'xxx'}}
,这时传递参数就得用params
了,接收参数是$route.parmas.username
,这里的name
还可以当做路径使用
通过url
动态路由传参,在路由设置的时候以:
冒号的形式传递参数,这就是对参数的绑定,path:'/params/:newsId/:newsTitle'
,在<router-link>
设置参数<router-link to="/params/198/vue-router">传递参数</router-link>
;在组件中接收参数,$route.params.newsId
;
通过url GET
传参,还可以在<router-link>
设置参数<router-link to="/content?newsId =123">传递参数</router-link>
;在组件中接收参数,$route.query.newsId
;
编程式导航
也就是通过JS
跳转路由,
this.$router.push('home')。
this.$router.push(name:'content',params:{userId:123});
路由模块化
单独写一个router.js
,并且在程序末尾导出router
实例,export default router
。在main.js
中import router from "../router.js"
路由其他
通过在实例中注入路由,我们可以在任何组件内通过this.$router
访问路由,也可以通过this.$router
访问当前路由。
单页面多路由区域操作,在<router-view name='自定义组件名'></router-view>
和components:{default: '默认组件' ,自定义组件名:'组件'}
,其中name
和 自定义组件名对应,
路由的重新定向,有时候我们的路径不一致,但希望到同一页面,这就需要页面重定向了redirect
。path
之后就不用写组件了,设置redirect
,参数为需求页面的path
值
alias
别名也可以实现重定向的效果,在path
和component
写完之后,设置alias
;用的时候路径就写alias
值,也会跳转到path
路径的页面;<router-link to="/alias">
;别名请不要用在path
为/
中,是不起作用的。
页面转场动画
路由的过渡动画,在<router-view>
外层加上<transition>
,组件过渡过程中,会有四个CSS
类名进行切换,这四个类名与transition
的name
属性有关,比如name="fade"
,过渡模式是默认的mode
模式in-out
模式,我们也可以设置为out-in
。如果想做出实用酷炫的过渡效果,可以用插件等工具。
history
模式
路由的mode
的设置为history
,可以省略浏览器显示的路径中的#
404
页面
404
页面,当用户地址输入错误,应该显示有好的提示信息,显示进入错误,{path:'*',component:Error}
,Error
组件可以做的好看好一点;
路由钩子函数
路由中的钩子函数,路由的钩子选项可以写在路由配置文件中,也可以写在我们的组件模板中。
在路由文件中我们只能写一个beforeEnter
,就是在进入此路由配置时。bdforeEnter
的钩子函数,需要传递三个参数beforeEnter:(to,from,next)=>{}
:
to
路由将要跳转的路径信息,信息是包含在对像里边的;from
路径跳转前的路径信息,也是一个对象的形式。next
路由的控制参数,常用的有next(true)
和next(false)
。相当于一个控制开关,确认是否跳转的。我们可以在这里做个判断语句,判断参数是否正确,路径是否正确,然后再跳转。
在模板中就可以有两个钩子函数可以使用:beforeRouteEnter
在路由进入前的钩子函数。beforeRouteLeave
在路由离开前的钩子函数。也可以轻易的读出to
和from
的值。记得一定写next()
,不然路由失败。
在业务逻辑代码中需要跳转页面我们如何操作,这就需要编程时导航了,$router.go(-1)
后退;$router.go(1)
前进;$router.push('xxx')
,xxx
可以是任意路径。这里是$router
,不是$route
。
生命周期
beforeCreate(){}
, 组件实例化之前执行的函数,一般做加载的动画
created(){}
, 组件实例化完成,但还没生成DOM
,页面还未显示。可以获取接口数据,赋给属性,还可以结束上面的加载动画。
beforeMount(){}
, 组件挂载前,页面仍未显示,但虚拟DOM
已配置
mounted(){}
, 组件挂载完成,此方法只会执行一次,此方法执行后,页面显示,请求网络数据,业务处理
beforeUpdate(){}
, 组件更新前,页面仍未更新,但虚拟DOM
已配置
updated(){}
, 组件更新后,此方法执行后,页面显示,一般我们在这里处理组件发生改变的情况
beforeDestory(){}
, 组件销毁前
destoryed(){}
, 组件已销毁
渲染机制
vm.$mount
为vue
渲染的主要函数
独立构建和运行时构建:
new vue
,执行初始化。- 挂载
$mount
方法,通过自定义render
方法、template
、el
等生成Render
函数。 - 通过
Watcher
监听数据变化。 - 当数据变化时,
Render
函数执行生成VNode
对象。 - 通过
patch
方法,对比新旧VNode
对象,通过DOM Diff
方法,添加修改删除真正的Dom
元素。
状态管理VUEX
vue
项目当中的非父子非兄弟组件之间的通讯传值可以用url、storage 和 cookie
,在小型项目中这样用是很好的。如果是大型项目,用vuex
就更合适,vuex
可以把所有的状态(参数)共享在一起,同时自动更新。
安装 vuex
npm install vuex --save
使用 vuex
- 在
src
文件夹下创建vuex
文件夹,然后在该文件夹内创建store.js
文件。 - 然后在
store.js
文件内引入vue
和vuex
,然后使用Vuex
,新建store
对象,我们就可以在store
中写state,mutations,getters,actions
,同时向外导出store
; - 也可以使用模块组
moudels
,每个module
都有自己的state、getter、mutation、actions
,并且要在store
中引入所有moudel
; store
下面的getter.js
和actions.js
,这两个主要是管理模块之间状态;- 在
mian.js
中 引入store
文件,在实例化Vue
对象时,加入引入的store
对象,这样就可以在所有子组件中使用vuex
了
state
state
,是vuex
自己维护的一份状态数据。数据的格式需要你根据业务去设计。
在组件中获取state
参数,有两种方式,
第一种就是直接取this.$store.state.xxx
;
第二种是使用映射函数mapState
函数取,先从vuex
引入mapState
( 引入的时候要用{}
) ,再mapState(["xxx"])
,当和其他计算属性同时使用的时候要用延展操作符...mapState(["xxx"])
,写在computed
里;
mutations
mutations
,更改Vuex
的store
中的状态的唯一方法就是mutations``。mutations
必须是同步函数。
每一个mutations
都有一个事件类型type
和一个回调函数handler
;
使用常量替代mutation
事件类型;待扩展。
在组件中调用mutations
里的方法,有两种方式:
- 第一种需要通过
this.$store.commit("xxx")
方法调用,可以添加第二个参数进行传参,$store.commit("xxx","xxx")
,也可以传入一个对象。 - 第二种是使用映射函数
mapMutations
调用,先从vuex
引入mapMutations
( 引入的时候要用{}
) ,再mapMutations["xxx"]
,当和其他方法同时使用要使用延展操作符...mapMutations (["xxx"])
,调用的时候可以直接传参,写在methods
里;
getters
getters
,可以把他看作在获取数据之前进行的一种再编辑,相当于对数据的一个过滤和加工。可以认为是store
的计算属性,就像计算属性一样,getter
的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters
接受state
作为其第一个参数,getters
也可以接受其他getters
作为第二个参数,你也可以通过让getter
返回一个函数,来实现给getter
传参,在你对store
里的数组进行查询时非常有用。
在组件中可以使用this.$store.getters.xxx
或者mapGetters["xxx"]
调用,与mapState
类似,也是写在computed
里。
在组件中设置了mapGetters
,在组件的beforeCreated
事件中,是取不到相应的值的,在created
之后,才能取到。???,待了解
actions
actions
,类似于mutations
,不同在于:actions
提交的是mutations
,而不是直接变更状态。actions 可以包含任意异步操作,而mutations
是同步操作。
Action
函数接受一个与store
实例具有相同方法和属性的context
对象,因此可以调用context.commit("xxx")
,提交一个mutation
,或者通过context.state
和context.getters
来获取state
和getters
。也可以传入{commit}
,直接commit("xxx")
,这里actions
的第一参数永远默认为是context
,很容易理解,因为我获取的是状态,也就是如果你直接写(commit)
的话,就必须写成(commit) => commit.commit.xxx
。
组件中使用的时候,有两种方式,this.$store.dispatch("xxx")
和...mapActions (["xxx"])
,写在methods
里。
moudels
moudels
,Vuex
只能有一个单一的store
对象,但是当应用变得庞大复杂的时候store
就可能变得非常的臃肿;所以 Vuex 允许我们将store
分割成模块module
。每个模块拥有自己的state、mutation、action、getter
,甚至是嵌套子模块——从上至下进行同样方式的分割。
对于模块内部的mutation
和getter
,接收的第一个参数是模块的局部状态对象state
。同样,对于模块内部的action
,局部状态通过context.state
暴露出来,根节点状态则为context.rootState
。对于模块内部的getter
,根节点状态会作为第三个参数暴露出来。
钩子函数
过滤filters:{ }
过滤符的使用;
混入
混入mixins
是一种分发Vue
组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
过渡和动画
显性的过渡时间
你可以用<transition>
组件上的duration
属性定制一个显性的过渡持续时间 (以毫秒计):
<transition :duration="1000">...</transition>
也可以定制进入和移出的持续时间:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
当有相同标签名的元素切换时,需要通过key
特性设置唯一的值来标记以让Vue
区分它们。
过渡模式
同时生效的进入和离开的过渡不能满足所有要求,所以Vue
提供了 过渡模式。
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。out-in
:当前元素先进行过渡,完成之后新元素过渡进入。
<transition name="fade" mode="out-in">
<!-- ... the buttons ... -->
</transition>
实例方法
vm.$set(target,key,value);
往对象中添加属性
ref
属性获取dom
节点
<div ref="box"></div>
this.$ref.box.style="xxx"
获取当前节点的属性
$event.target.style.color="red"
网络请求
vue-resource
vue
自己的资源请求工具,直接在main.js
中import
引入,然后Vue.use(vue-resource)
,之后再所有组件中都可以使用了。this.$http.get(url).then((res)=>{},(err)=>{})
axios
第三方工具,在哪用就在import
引入,axios.get(url).then(()=>{}).catch()
UI框架
Mint-UI 移动端的UI框架
https://mint-ui.github.io/docs/#/zh-cn2
//在main.js 中,
import Mint from 'mint-ui';
import 'mint-ui/lib/style.css'
Vue.use(Mint);
Element-UI PC端的UI框架
http://element-cn.eleme.io/#/zh-CN/component/installation
//在 mian.js 中,
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
字体文件如果报错,webpack.config.js
配置file_loader
{
test: /.(eot|svg|ttf|woff|woff2)(?S*)?$/,
loader: 'file-loader'
}