Vue2
认识
概念
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统
<div id="app">
  {{ message }}
</div>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})
v- attribute 被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。
它们会在渲染的 DOM 上应用特殊的响应式行为
- JavaScript 框架
 - 简化 Dom 操作
 - 响应式数据驱动
 
核心
- 数据绑定
 - 事件绑定
 - 用户输入获取
 - 组件定义和使用
 
引入
CDN
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
Vue CLI
安装
npm install -g @vue/cli
升级
npm update -g @vue/cli
创建项目
vue create project-name
安装必要工具
npm install
开启本地端口
npm run serve
npm run serve -- --port 5000
基础
Vue 实例
var app = new Vue({
    el:"#app",
    data:{
        message:"Hello World",
        array:[],
		obj:{},
    }
})
- el:挂载点,
- Vue 会管理 el 选项命中的元素及其内部的后代元素
 - 可以挂载到双标签上,不能使用 HTML 和 BODY
 
 - data:数据对象
- Vue 中用到的数据定义在 data 中
 - data 中可以写复杂类型的数据
 - 渲染复杂类型数据时,遵守 js 的语法即可
 
 
Vue 指令
Vue 指令指的是,以 v- 开头的一组特殊语法
v-text
设置标签的文本值 (textContent)
支持在内部写表达式,如 v-text="message + '!'"
v-text 指令无论内容是什么,只会解析为文本
var app = new Vue({
    el: "#app",
    data: {
        message: "Hello"
    }
})
默认写法:在文本标签中添加 v-text 属性值,会替换全部内容
<div id="app">
    <h2 v-text="message"></h2>
</div>
差值表达式 {{ }} 可以替换指定内容
<div id='app'>
        <p>{{message + '!'}}</p>
</div>
v-html
设置标签的 innerHTML
若内容中有 html 结构,会被解析为标签,如 content:"<a href='#'>Hello World</a>"
辨析:解析文本使用 v-text,需要解析 html 结构使用 v-html
var app = new Vue({
    el:"#app",
    data:{
        content:"Hello World"
    }
})
<div id="app">
    <p v-html="content"></p>
</div>
v-on
为元素绑定事件
- 
事件名不需要写 on
 - 
指令可以简写为 @
 - 
绑定的方法定义在 methods 属性中
 - 
方法内部通过 this 关键字可以访问定义在 data 中数据
 
var app = new Vue({
    el: "#app",
    methods: {
        doIt: function () {
            // ...
        }
    }
})
<div id="app">
    <input type="button" value="bind1" v-on:click="doIt">
    <input type="button" value="bind2" v-on:monseenter="doIt">
    <input type="button" value="bind3" v-on:dblclick="doIt">
    <input type="button" value="bind4" @dblclick="doIt">
</div>
例:计数器
<div id="app">
    <input type='button' value='-' v-on:click='sub'>
    <span>{{value}}</span>
    <input type='button' value='+' v-on:click='add'>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            value: 1
        },
        methods: {
            sub: function () {
                this.value -= 1;
            },
            add: function () {
                this.value += 1;
            }
        },
    })
</script>
修饰符
事件的后面跟上 .修饰符 可以对事件进行限制
.stop- 调用event.stopPropagation()。.prevent- 调用event.preventDefault()。.capture- 添加事件侦听器时使用 capture 模式。.self- 只当事件是从侦听器绑定的元素本身触发时才触发回调。.{keyCode | keyAlias}- 只当事件是从特定键触发时才触发回调。.native- 监听组件根元素的原生事件。.once- 只触发一次回调。.left- (2.2.0) 只当点击鼠标左键时触发。.right- (2.2.0) 只当点击鼠标右键时触发。.middle- (2.2.0) 只当点击鼠标中键时触发。.passive- (2.3.0) 以{ passive: true }模式添加侦听器
<!-- 方法处理器 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>
<!-- 内联语句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 动态事件缩写 (2.6.0+) -->
<button @[event]="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!--  串联修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 键修饰符,键别名 -->
<input @keyup.enter="onEnter">
<!-- 键修饰符,键代码 -->
<input @keyup.13="onEnter">
<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 对象语法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
v-show
根据表达值的真假,切换元素的显示和隐藏
- 原理是修改元素的 display,实现显示隐藏
 - 指令后面的内容,最终都会解析为布尔值
 
var app = new Vue({
    el:"#app",
    data:{
        isShow:false,
        age:16
    }
})
<div id="app">
    <img src="地址" v-show="true">
    <img src="地址" v-show="isShow">
    <img src="地址" v-show="age>=18">
</div>
v-if
根据表达值的真假,切换元素的显示和隐藏 (操纵 dom 元素)
- 本质是通过操纵 dom 元素来切换显示状态
 - 表达式的值为 true,元素存在于 dom 树中,为 false,从 dom 树中移除
 - 辨析:频繁的切换使用 v-show,偶尔切换使用 v-if,前者的切换消耗小
 
var app = new Vue({
    el:"#app",
    data:{
        isShow:false,
    }
})
    <div id="app">
      <p v-if="true">我是一个p标签</p>
      <p v-if="isShow">我是一个p标签</p>
      <p v-if="表达式">我是一个p标签</p>
    </div>
v-bind
设置元素的属性:v-bind:属性名=表达式
- 可以用 
:简写 - 需要动态的增删 class 建议使用对象的方式
 
var app = new Vue({
    el:"#app",
    data:{
        imgSrc:"picture-path",
        imgTitle:"text",
        isActive:false
    }
})
<div id="app">
    <img v-bind:src= "imgSrc" >
    <img v-bind:title="imgTitle+'!'">
    <img v-bind:class="isActive?'active':''">
    <img v-bind:class="{active:isActive}">
</div>
v-for
根据数据生成列表结构
- 语法:
(item, index) in array - item 和 index 可以结合其他指令一起使用
 - 数组长度的更新会同步到页面上,是响应式的
 
var app = new Vue({
    el: "#app",
    data: {
        arr: ['a', 'b', 'c', 'd', 'e'],
        objArr: [
            { name: 'Mike' },
            { name: 'Jack' }
        ]
    }
})
<div id="app">
    <ul>
        <li v-for="(item,index) in arr" :title='item'>
            {{index}} -> {{ item }}
        </li>
        <li v-for="item in objArr">
            {{ item.name }}
        </li>
    </ul>
</div>
v-model
获取和设置表单元素的值 (双向数据绑定)
- 绑定的数据会和表单元素值相关联
 
<div id="app">
    <input type="text" v-model="message" />
</div>
组件间的数据传递
父子组件之间的数据传递可以使用 props 或者 $emit 等方式
父传子
使用 props
子组件部分
父组件部分
子传父
通过事件传递数据
子组件部分
父组件部分
一些原理
计算属性 computed 中的 getter
在 Vue 中,computed 的属性可以被视为是 data 一样,可以读取和设值,因此在 computed 中可以分成 getter(读取) 和 setter(设值),一般情况下是没有 setter 的,computed 预设只有 getter ,也就是只能读取, 不能改变设值。
vue.js 计算属性默认只有 getter,因为是默认值所以我们也常常省略不写,如下代码:
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})
其实 computed 里的代码完整的写法应该 是:
computed: {
    fullName: {
      get(){
         return this.firstName + ' ' + this.lastName
      }
    }
  }
axios
介绍
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
引入
使用 npm:
$ npm install axios
使用 bower:
$ bower install axios
使用 cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
样例
axios({
    method: 'GET',
    url: url,
})
.then(res => {console.log(res)})
.catch(err => {console.log(err)})
axios.post('/user', {
    firstName: 'Mike',
    lastName: 'Allen'
}).then( res => {
    console.info(res)
}).catch( e => {
    console.info(e)
})
使用
axios(config)
// 发送 POST 请求
axios({
  method: 'post',
  url: 'www.google.com',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});
axios(url[, config])
// 发送 GET 请求(默认的方法)
axios('/user/12345');
别名
axios.get(url[, config])
axios.post(url[, data[, config]])
配置项
{
  // `url` 是用于请求的服务器 URL
  url: '/user',
  // `method` 是创建请求时使用的方法
  method: 'get', // 默认是 get
  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',
  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
  transformRequest: [function (data) {
    // 对 data 进行任意转换处理
    return data;
  }],
  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对 data 进行任意转换处理
    return data;
  }],
  // `headers` 是即将被发送的自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},
  // `params` 是即将与请求一起发送的 URL 参数
  // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
  },
  // `paramsSerializer` 是一个负责 `params` 序列化的函数
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },
  // `data` 是作为请求主体被发送的数据
  // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时 ,必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
  },
  // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  timeout: 1000,
  // `withCredentials` 表示跨域请求时是否需要使用凭证
  withCredentials: false, // 默认的
  // `adapter` 允许自定义处理请求,以使测试更轻松
  // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
  adapter: function (config) {
    /* ... */
  },
  // `auth` 表示应该使用 HTTP 基础验证,并提供凭据
  // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },
  // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // 默认的
  // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
  xsrfCookieName: 'XSRF-TOKEN', // default
  // `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的
  // `onUploadProgress` 允许为上传处理进度事件
  onUploadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },
  // `onDownloadProgress` 允许为下载处理进度事件
  onDownloadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },
  // `maxContentLength` 定义允许的响应内容的最大尺寸
  maxContentLength: 2000,
  // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认的
  },
  // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
  // 如果设置为0,将不会 follow 任何重定向
  maxRedirects: 5, // 默认的
  // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
  // `keepAlive` 默认没有启用
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),
  // 'proxy' 定义代理服务器的主机名称和端口
  // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
  // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: : {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },
  // `cancelToken` 指定用于取消请求的 cancel token
  // (查看后面的 Cancellation 这节了解更多)
  cancelToken: new CancelToken(function (cancel) {
  })
}
工程化目录结构
脚手架

架构
main.js
程序入口
App.vue
主视图
<template>
  <div id="app">
    <div>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view />
  </div>
</template>
<script>
export default {};
</script>
<style lang="scss">
</style>
结构:<template>
脚本: <script>
样式:<style>
页面中放入一个路由视图容器:
<router-view></router-view>
引用路由链接:
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
router
路由配置例
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  }
]
用 Vue.js + Vue Router 创建单页应用
使用 Vue.js ,我们已经可以通过组合组件来组成应用程序;当你要把 Vue Router 添加进来,我们需要做的是,将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们。
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div> 
单文件组件
Vuex
认识
vuex 是一个专门为 vue.js 应用程序开发的状态管理模式。
核心思想:把组件的共享状态抽取出来,以一个全局单例模式进行管理

五类对象
- state:存储状态(变量)在组件中使用 
$store.state.foo - getters:对数据获取之前的再次编译,可以理解为 state 的 computed 属性。在组件中使用 
$store.getters.fun() - mutations:修改状态,并且是同步的。在组件中使用 
$store.commit('funcName',params)。它和组件中的自定义事件类似。 - actions:异步操作。在组件中使用是 
$store.dispath('funcName',params) - modules:store 的子模块,为了开发大型项目,方便状态管理而使用的。
 
简单配置
main.js
Vuex 提供了一个从根组件向所有子组件,以 store 选项的方式 “注入” 该 store 的机制
//main.js内部对store.js的配置
import store from '"@/store/store.js' 
//具体地址具体路径
new Vue({
    el: '#app',
    store, //将store暴露出来
    template: '<App></App>',
    components: { App }
});
store/index.js
import Vue from 'vue'; //首先引入vue
import Vuex from 'vuex'; //引入vuex
Vue.use(Vuex) 
export default new Vuex.Store({
    state: { 
        // state 类似 data
        //这里面写入数据
    },
    getters:{ 
        // getters 类似 computed 
        // 在这里面写个方法
    },
    mutations:{ 
        // mutations 类似methods
        // 写方法对数据做出更改(同步操作)
    },
    actions:{
        // actions 类似methods
        // 写方法对数据做出更改(异步操作)
    }
})
或者
mport Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {}
const getters = {}
const mutations = {}
const actions = {}
const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})
export default store;
但更建议的做法是:在单独的文件里写好每个组件的状态,最后统一在 index.js 中引入
项目结构
├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块
对象
state
state 中存放状态对象
const state = {
    todos: [
        { id: 1, title: "Wake up", done: false },
        { id: 2, title: "Learn", done: false },
    ]
}
以形似 $store.state.todos 或  $store.state.todo.todos (如果此状态分模块单独存放的话)调用
getters
getters 里存放着从 state 中派生出来的一些状态,类似于 computed,所以 getters 里的状态都具有相应的依赖值,而且以函数的形式进行定义
const getters = {
    doneTodos: state => {
        return state.tasks.filter(task => task.done)
    },
    doneTodosNum: (state, getters) => {
        return getters.doneTodos.length
    }
}
注意,getter 也可以接受其他 getter 作为第二个参数
通过属性访问
getter 会暴露为 store.getters 对象,可以以属性的形式访问这些值,如 $store.getters.doneTodoNum,不分组件
通过方法访问
也可以通过让 getter 返回一个函数,来实现 给 getter 传参。在对 store 里的数组进行查询时非常有用
getTodoById: state => id => {
        return state.todos.find(todo => todo.id === id)
    }
// 调用时
$store.getters.getTodoById(2)
注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果
mutations
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
const mutations = {
    addTask(state, newTaskTitle) {
        console.log('add: ' + newTaskTitle);
        let newTask = {
            id: Date.now(),
            title: newTaskTitle,
            done: false,
        };
        state.tasks.push(newTask);
        newTaskTitle = "";
    },
}
要唤醒一个 mutation handler,需要以相应的 type 调用 store.commit 方法,如 $store.commit('mutations','Sleep'),不分组件
载荷
传入的额外参数称为载荷(payload)
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
// 调用时
store.commit('increment', {
  amount: 10
})
type 属性
提交 mutation 的另一种方式是直接使用包含 type 属性的对象
store.commit({
  type: 'increment',
  amount: 10
})