读音 viewJs, 一个mvvm前端框架,和angular类似,但是比较小巧,容易上手。
特点:模板渲染(双向绑定)、模块化(组件)、路由、ajax、数据流、轻量快速
中文官网:https://cn.vuejs.org
2016年10月份发布的2.0版本
Vue 不支持Ie8及以下版本,因为Vue使用了IE8无法模拟的ECMAScript 5 特性。
浏览器插件 Vue Devtools 方便调试
2.下载好后进入vue-devtools-master工程 执行npm install ----->npm run build.
3.进入shells chrome 修改manifest.json 中的persistent为true
4.打开谷歌浏览器更多工具--->扩展程序—》加载已解压的扩展程序---》添加工程中的shells-->chrome的内容。
引入方式:
script标签引入 ,vue会被注册为一个全局变量
NPM安装 npm install vue 需要nodejs
vue-cli 官方提供的脚手架
1.安装
npm install vue-cli -g
2.初始化项目
vue init webpack my-project
3.安装项目依赖
npm install //在my-project文件夹下执行
npm run dev 在localhost启动测试服务器
npm run build 生成线上目录 dist
权限不足的话用sudo
语法
Vue实例对象
var vm = new Vue({ //全局构造函数
el:’#myApp’, //选取数据作用范围 可id class
data:{
message:’hello vue’ //创建message变量
}
});
实例生命周期
beforeCreate:function(){
console.log("实例创建前");
},
created:function(){
console.log("实例创建完毕后执行");
},beforMount(挂载)…mounted…beforeUpdate(数据更新)…updated…beforeDestroy(销毁前后)..destroyed...
全局API
Vue.set 设置vue对象的属性
Vue.delete 删除vue对象的属性
Vue.component 添加全局组件
Vue.use 使用插件
实例选项
el:设置作用范围
data:数据设置 get set
props:接收父组件的数据
Computed:即使计算
method:创建函数
watch:监控
template:模板
filters:过滤器
componts:子组件
reander: h=>h(app) es6 相当于 reder:function(h){ return h(app) } h接受了app方法
实例属性
vm.$data 实例的数据对象
vm.$props 当前组件收到的props
vm.$el 实例使用的根dom元素
vm.$parent 父实例
vm.$root 当前组件树的根Vue实例
vm.$children 当前实例的直接子组件
实例方法
vm.$watch 监视一个表达式或计算属性函数,回调新值旧值
vm.$set 全局Vue.set
vm.$delete 全局Vue.delete
实例事件
实例生命周期方法
模板语法
文本
{{ data }} 输出变量 双向
<h1 v-text=“message”</h1> 输出变量 双向
<h1 v-html="message"></h1> //输出html内容
<h1 v-once>单向绑定: {{ message }}</h1> 单向
<h1 v-bind:title=“message”></h1> 属性渲染 简写:title 动态绑定 改变时同步
表达式
{{ number + 1 }}
{{ result ? ’YES’ : ’NO'}}
指令
v-model 双向数据绑定 绑定form元素
v-show 符合表达式时显示 页面是display:none
v-if 符合表达式显示 页面是没有的
提交事件
v-on:submit=“submitForm” 简写@submit=“submitForm"
el:’app’,
methods:{
submitForm:function(e){
//事件处理
e.preventDefault();//阻止提交 如果不写需要在表单处$submit.prevent=“submitForm” 使用修饰符 效果是一样的 阻止提交
}
}
点击事件
v-on:click
v-bind缩写 v-bind:class => :class
v-on缩写 v-on:click => @click
实时计算
computed
<div id="app">
<h1>computed</h1>
{{ username }}
<input type="text" v-model="first">
<input type="text" v-model="last">
</div>
new Vue({
el: '#app',
data: {
first: 'david',
last: 'bai'
},
computed: {
username: function() {
return this.first + '-' + this.last;
}
}
});
计算setter
computed: {
fullName: {
get: function () {
return this.firstName + ' ' + this.lastName
},
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
监视watch
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 question 发生改变,这个函数就会运行
question: function (newQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
}
绑定css
<div v-bind:class=“{active : isActive}"></div> 表达式为真时显示
<li :class="task.status == 1 ? 'red' : '' " v-for='task in tasks’>
<li :class=“{‘class1’,’class2’,status?’abc’:’’}” //两个样式加一个条件判断样式
绑定style
<div v-bind:style=“{color:activeColor,fontSize:fontsize+’px'}">
条件
<p v-if='number==1'>1</p>
<p v-else-if='number==3'>3</p>
<p v-else>default</p>
key唯一值
<template v-if="loginType === 'username' ">
<label>Username</label>
<inputplaceholder="Enter your username" key="username-input" >
</template>
<templatev-else>
<label>Email</label>
<inputplaceholder="Enter your email address" key="email-input" >
</template>
遍历
v-for
<li v-for='item in items’> {{item}}<li> //数组
<li v-for=‘item in items'>{{item.title}}</li> //对象集合
<li v-for=‘(item,index) in items’>{{index}} . {{item.title}}</li> //第二个参数作为索引
<li v-for=‘obj in object’>{{ value }}</li> //遍历对象
<li v-for=‘(value,key) in object’>{{key}}:{{value}}</li> //第二个参数键名
<li v-for=‘(value,key,index) in object’>{{index}}</li> //第三个参数为索引
<li v-for=‘item in items’ :key=’item.id’></li> //:key 类似于track-by=$index
<li v-for=‘item in items’ v-if=‘!item.isComplete’></li> 只传递false的
也可以用of 替代in item of items 这是javascript迭代器的语法
v-pre 不需要编译
v-cloak 隐藏未编译的{{}}标签 配合样式使用 [v-cloak]{display:none}
组件
//全局组件
Vue.component('my-header',{
template:'<p>this is my-header </p>'
})
//组件树
//孙子组件
var myheaderChild={
template:'<p>this is my header Child {{ name }}</p>',
data (){ //es6 类似data:function(){} 避免引用赋值
return { name:'mao' }
}
}
//子组件
var myheader={
template:'<p><my-header-Child></my-header-Child> this is my header </p>',
components:{
'my-header-Child':myheaderChild
}
}
//实例对象
new Vue({
el:'#app',
components:{
'my-header':myheader
}
})
//静态数据传递
<david heading=“usps"></david>
<david heading=“fedex"></david>
<template id=“david-template”>
{{heading}}
{{count}}
</teamplate>
//全局注册
Vue.component(‘david’,{
template:’#david-template’, //模板id
props:[‘heading’] //变量用作模板内
});
因为html不区分大小写 所以驼峰命名用-分开 不要些comA
<com-a number='5'></com-a>
子组件中使用props:['number'], 接受一下 就可以使用了
//动态数据传递
<com-a :my-value='myVal'></com-a>
props:['number','my-value’], {{ myValue }}
子组件事件传递
子组件中
this.$emit('my-event',this.msg)
父组件
<com-a number='5' :my-value='myVal' @my-event='getMyEvent'></com-a>
methods:{
getMyEvent(param){
alert(param) //param 从子组件中拿到的数据
}
}
父组件向子组件插入模版
<com-a number='5' :my-value='myVal' @my-event='getMyEvent'>
<p>我来自父组件</p>
</com-a>
子组件中使用
<slot></slot>
插入多个slot 命名插入
<div slot='header'>我来自header</div>
<p>我来自父组件</p>
<div slot='footer'>我来自footer</div>
子组件中
<slot name='header'></slot>
<slot></slot>
<slot name='footer'></slot>
动态组件
根据currentView的改变而动态改变组件 类似路由
<p :is="currentView"></p>
data (){
return{
currentView:'com-a',
myVal: 10
}
},
Keep-alive
<keep-alive>
<p :is="currentView"></p>
</keep-alive>
如果使用keep-alive包含起来,进行切换组件时会将模版缓存起来
Css过渡效果
使用transtition组件
<transition name="fade">
<p v-show='show'> i am show</p>
</transition>
css过渡
transition组件会根据不同阶段给不同的类名
进入阶段
V-enter 完全不显示
V-enter-active 进入显示阶段
离开阶段
V-leave 已经显示
V-leave-active 到完全不显示
设置样式
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to {
opacity: 0
}
也可以使用animate.css
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
来自定义样式
js过渡
通过事件钩子 来实现过渡
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
</transition>
js中
methods: {
// 进入中
beforeEnter: function (el) {
// ...
},
// 此回调函数是可选项的设置
// 与 CSS 结合时使用
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// 离开时
beforeLeave: function (el) {
// ...
},
// 此回调函数是可选项的设置
// 与 CSS 结合时使用
leave: function (el, done) {
// ...
done()
},
afterLeave: function (el) {
// ...
},
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) {
// ...
}
}
el 当前transition里的元素
自定义指令
<p v-color="'red'">v-color自定义指令</p>
directives:{
color:function(el,binding){
el.style.color=binding.value
},
color2:function(){
}
},
写在组件中 作用域只在组件中 写在全局vue实例中 则全组件可用
mixins
复用混合对象
// 定义一个混合对象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定义一个使用混合对象的组件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
过滤器
自定义过滤器
<!-- in mustaches -->
{{ message | capitalize }}
<!-- in v-bind -->
<div v-bind:id="rawId | formatId"></div>
new Vue({
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
单文件组件
*.vue 结尾
css使用scoped 则只在组件中使用,否则全局都有这个样式 泄漏到父级
<style scoped></style>
vue-router插件
npm install vue-router
路由
//引入路由
import VueRouter from 'vue-router’
//引入子组件
import about from './components/about'
import news from './components/news'
//使用全局使用
Vue.use(VueRouter)
//实例化router
let router = new VueRouter({
routes: [
{
path:'/about',
component:about
},
{
path:'/news',
component:news
}
]
})
//实例Vue
new Vue({
el: '#app',
router:router
})
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link :to="{path:’about’}">about</router-link>
<router-link :to="{path:'news'}">news</router-link>
<!-- 路由出口 -->
<router-view></router-view>
路由参数
path:'/about/:id’, http://localhost:8080/#/about/1
:设置id参数 /:id/detail/:color 就必须严格输入detail /about/3/detail/red
获取参数
this.$route.params
添加参数后 路径中必须输入参数 否则无法访问到about
router默认使用hash模式
/#/about
mode: 'history’, 会显示正常的页面url
/about
嵌套路由
routes: [
{
path:'/about/', //path:'/about/:id',
component:about,
children:[
{
path:'about1',
component:about1
}
]
},
{
path:'/news',
component:news
}
]
子组件只会渲染到第一个父组件 所以about.vue也要增加router-view
about下
<router-link :to="{path:'/about/about1'}">about_about1</router-link>
<router-link to="/about/about1">等于path</router-link>
<router-view></router-view>
路由重定向
{ path: '/a', redirect: '/b’ }
命名路由
routes: [ { path: '/user/:userId', name: 'user', component: User }
命名视图
<router-view class="view two" name="a"></router-view>
vuex 状态管理插件
store统一管理中心
component每一个组件更新 通知 store 再从stroe通知每个调用他的更新
npm install vuex
import Vuex from 'vuex'
Vue.use(Vuex)
//实例化store
let store = new Vuex.Store({
state:{
totalPrice:0
},
mutations:{
increment(state,price){
state.totalPrice +=price
},
decrement(state,price){
state.totalPrice -=price
}
}
})
//实例化vue
new Vue({ //只有一个实例
el: '#app',
store
})
app.vue页面中访问属性
{{ this.$store.state.totalPrice }}
子组件中
<button @click="add">add</button>
<button @click="minus">minus</button>
methods:{
add(){
this.$store.commit('increment',this.price)
},
minus(){
this.$store.commit('decrement',this.price)
}
}
也可以通过action的方式
//实例化store
let store = new Vuex.Store({
state:{
totalPrice:0
},
mutations:{
increment(state,price){
state.totalPrice +=price
},
decrement(state,price){
state.totalPrice -=price
}
},
actions:{
increase(context,price){
//context 当前store
//api(pic,function(){
//请求api后 再回调
//})
context.commit('increment',price)
}
}
})
Add方法中需要调用dispatch actionname
add(){
//this.$store.commit('increment',this.price)
this.$store.dispatch('increase',this.price)
},
这样的好处是actions可以和后端接口操作
使用getters
let store = new Vuex.Store({
state:{
totalPrice:0
},
mutations:{
increment(state,price){
state.totalPrice +=price
},
decrement(state,price){
state.totalPrice -=price
}
},
actions:{
increase(context,price){
//context 当前store
//api(pic,function(){
//请求api后 再回调
//})
context.commit('increment',price)
}
},
getters:{
getTotal(state){
return 'getters里的' + state.totalPrice
}
}
})
前台拿数据{{ this.$store.getters.getTotal }}
这样是一个方法可以加一些判断
Modules
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
vue-resource插件
npm install vue-resource
import VueResource in ‘vue-resource’
Vue.user(VueResource)
就可以在全局使用this.$http
//get请求
this.$http.get(‘getList’).then(function(response){
//sucuss
response.data
},function(error){
//error
})
//post请求
this.$http.post(‘update’,{userId:111}).then((response) => { this.newsList = response.data })
json-server 模拟api数据
Vue-slide 幻灯片插件
Vue-datepicker 日期插件
反向代理 https 的有问题 改为http
axios http请求
axios.get('user?id=1')
.then(funciton()){
}