
前端不是我的主业,不过太久不用,捡起来每次都觉得头疼,还是稍微做点笔记吧。
首先是官方文档:https://cn.vuejs.org/v2/guide/,虽然目前到3版本了,还是先了解下v2版本的知识,并不复杂。
一、基本方法
基本就是官网内容。
-
格式
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<div id="app">
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})

-
数据绑定、css绑定、事件绑定和语法糖
v-bind:value=<expression>
单项绑定,语法糖 :value=<expression>
v-model:value=<expression>
双向绑定(只用表单),语法糖 v-model=`
v-bind:class=xxx
,语法糖 :class=<str>
v-on:click.stop=<expression>
事件绑定,语法糖 @click.stop=<expression>
-
计算属性
func 里this指针指向的是vm
computed不吃性能,尽量用它
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
}
},
mounted(){
}
})
由vue管理的method,要以普通方式定义。
否则应该用箭头函数,例如:
getAnswer: function (()=>{})
此时它的this为window。
另外,指令directive相关的 this 都是 window
-
循环语句和条件语句
循环:
<ul id="example-1">
<li v-for="item in items" :key="item.message">
</li>
</ul>
<ul id="example-2">
<li v-for="(item, index) in items">
- -
</li>
</ul>
<div v-for="(value, name, index) in object">
. :
</div>
条件:
<div v-if="type === 'A'"></div>
<div v-else-if="type === 'B'"></div>
<div v-else-if="type === 'C'"></div>
<div v-else></div>
-
Vue 无法监控数组内容的改变
https://cn.vuejs.org/v2/guide/list.html#数组更新检测
对象因为有setter和getter,修改model可以监控到,view也会变动。
但直接操作数组不奏效,因为数组没有这两个方法,引发view变动则需要调用如下方法:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
-
过滤器,用于一些常见的文本格式化
-
生命周期
一旦 data 数据变化就会重新解析模版。
-
组件
-
创建
<template>
</template>
<script>
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'
export default {
name: ''
data(){
},
components: {
ComponentA,
ComponentC
},
// ...
}
</script>
<style>
</style>
或者
const vc = Vue.extend({ })
-
注册
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
-
使用
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
-
原型对象prototype
实例的隐式原型属性 __prototype__
永远指向类(父类)的原型对象

国内代理备忘
npm init
npm config set proxy http://10.101.1.1:8118
npm config set https-proxy http://10.101.1.1:8118
npm i -S vue
-
命令备忘
npm install -g @vue/cli
vue --version
vue create hello-world

修改配置,在vue.config.js
中添加(参考配置)
module.exports = {
devServer: {
host: '0.0.0.0',
port: 80
}
}


文件预览

-
render

vue.runtime.xxx.js 是运行版的vue,没有模版解析器,不能使用template配置项。
-
vue ref,vue用于获取元素,用来代替以前通过id获取元素的办法。
-
数据传递prop
相当于后端中一个类class实例的只读属性,。
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
-
混入 (mixin)
有点类似于后端的基类和子类,mixin属于基类的方法,多个子类都可以使用基类的方法。
var vm = new Vue({
mixins: [mixin],
methods: {
...
}
})
可以全局混入,也可以局部混入。
-
插件
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
-
scope
解决style类名相同,引入顺序不同,导致冲突的问题。
不要在App里使用scoped
三、开发步骤(入门)
官网的一些内容和后端思维是互通的,比如状态提升
之类的,不要害怕,见人说人话,见鬼说鬼话。
-
拆分静态组件,按功能点拆分
-
静态组件,不考虑交互
- 把html整个塞到app里
- 把一个组件的html剪切后立马写占位符,然后塞到组件里。
- 把样式也拆了,塞到组件,style加个scoped。
-
数据交互设计
类似于后端,设计数据库和model。
组件通信的几种方式:
-
通过 props 存储数据,数据存在App上。
- 父组件定义data,通过props传给子组件(子要在props里接收)
- 父组件定义method,通过props传给另一个子组件
- 注意子组件的v-model不要改props
相当于内存存变量。
-
自定义事件
子组件给父组件传数据用。
在父组件中给子组件绑定自定义事件,事件回调在父组件。(父给子传函数,要求子返回数据)
-
全局事件总线
定义一个所有组件的子组件vc(也可以直接用vm)挂在prototype上,然后使用事件触发。相当于后端的redis。多读单写
-
消息订阅&发布
全局事件总线和消息订阅其实差不多的效果。多读单写
-
浏览器localstorage,相当于后端的数据库DB。
-
vuex
多读多写
-
动态组件
不同功能的增删查改+统计信息变动
- 查
- 增删,事件event。
- 改
四、高级
-
自定义事件
this.$emit('myEvent')
<my-component v-on:my-event="doSomething"></my-component>
this.$off('myEvent')
this.$off(['myEvent','xxx'])
this.$off()
也适用于子给父组件传输数据。

自定义事件由父组件运行,props方式由子组件运行。
还可以通过ref绑定自定义事件。

-
全局事件总线
定义一个所有组件的子组件vc,然后赋值给prototype。

改良版:
把vm当成所有组件的子组件,这样子?真是奇妙。


-
消息订阅&发布
$ npm -i pubsub.js
import pubsub from 'pubsub-js'
pubsub.publish('hello',666)
pubsub.subscribe('hello',function(msgName,data){ })
pubsub.subscribe('hello',(msgName,data)=>{ })
-
nextTick
-
动画/过渡
其实就是封装了一个 transition 标签。
<transition name"xxx" appear></transition>
.xxx-enter-active{
animation: kelu 1s linear;
}
.xxx-leave-active{}
@keyframs kelu {
from{
transform: xxx
}
to{}
}

第三方动画:Animate.css:http://animate.style
-
跨域
axios请求,
cors(后端解决),代理服务器(前端解决)
module.exports = {
devServer: {
proxy: 'http://localhost:4000'
}
}
module.exports = {
devServer: {
proxy: {
'/api': {
target: '<url>',
ws: true,
changeOrigin: true
},
'/foo': {
target: '<other_url>'
}
}
}
}
# https://github.com/chimurai/http-proxy-middleware#proxycontext-config


-
插槽
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
-
vuex
npm i vuex
import Vuex from 'vuex'
Vue.use(Vuex)

import { createApp } from 'vue'
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state) {
state.count++
}
}
})
const app = createApp({ /* 根组件 */ })
// 将 store 实例作为插件安装
app.use(store)
dispatch -> commit ->
vc -> Action(ctx,value) -> mutation(state,value)
dispatch可以跳过,直接commit就行了。
mapState
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}

-
路由
npm i vue-router@3
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
<router-view></router-view>
# 一级路由
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
path: 'profile',
component: UserProfile,
},
{
path: 'posts',
component: UserPosts,
},
],
},
]
-
路由传参
-
query参数
-
params参数
-
props(对象/函数/布尔)

解构赋值,连续解构赋值:


-
路由命名
-
路由历史记录
声明式 |
编程式 |
<router-link :to="..." replace> |
router.replace(...) |
<router-link :to="..."> |
router.push(...) |
路由缓存:
<keep-alive :include="['xx','yy']">
<router-view></router-view>
</keep-alive>
路由组件新增了两个生命周期
-
路由权限
数据存在meta里,
前置路由守卫,主要做鉴权
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
后置路由守卫作用,一般就是修改页面内容之类的。
其他
-
字面量赋值
