此学习笔记是看网易云课程的学习笔记。
#下载node,配置环境变量
#初始化一个vue项目
npm install -g vue-cli #安装 vue-cli
vue init webpack test1 #初始化一个vue项目
cd test1 #进入项目
npm install #安装依赖
npm run dev #运行项目
#项目目录结构
index.html 项目根目录视图
.postcssrc.js: postcss配置文件
static: 静态文件目录
#模版语法
Vue 组件
包含三个部分:
templete: 视图
script: 逻辑
style: 样式
Mustache:模版
表现语法: {{ 语法 }} 只能存在单行语句,并且不能作用在HTML属性
Vue基本指令:
v-html: 渲染文本
v-text: 渲染文本
v-bind: 绑定 简写: v-bind:title == :title
条件渲染:
v-if
v-else
v-else-if
v-show
v-if与v-show区别:
v-if是"真正"的条件渲染,因为它会确保在切换过程中条件块内的事件监听器
和子组件适当地被销毁和重建
v-if 也是惰性的: 如果在初始渲染时条件为假,则什么也不做一直到条件第
一次变为真时,才会开始渲染多件块。
相比之下,v-show就简单得多,不管初始化条件是什么,元素总会被渲染,
并且只是简单地基于css进行切换。
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,
如果需要非常频繁地切换,则使用v-show较好,如果在运行时条件很少改变,
则使用v-if较好
列表渲染:
v-for:
例子:
names: ["lisa","qiqi","mali","deyi"]
<ul>
<li v-for="(name,index) in names">{{name}}--{{index}}</li>
</ul>
事件监听:
v-on: 简写: v-on:click == @:click
methods:
事件参数:
可以加 $event参数,代表事件本身
eg:
<a @click="add">{{age}}</a>
methods: {
add: function(event) {
this.age ++;
console.log(event);
}
}
修饰符:
事件修饰符
.stop 阻止冒泡
.prevent 阻止默认方法
.capture
.self
.once 事件只有一次
.passive
按键修饰符
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
...
数组更新检测:
如果此数组总在了视图,使用下列方法触发数组,会对视图进行更新。
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
eg:
data () {
return {
names: ["lisa","qiqi","mali","deyi"]
}
},
methods: {
push: function () {
this.names.push(["zhangsan"]);
}
<ul><li v-for="(name,index) in names" v-bind:key="index">{{name}}--{{index}}</li></ul>
<a @click="push"> push ele</a>
变异方法:上面方法,会引起视图更新
替换数组:不会引起视图更新
显示过滤/排序结果: filter
for后面指定的是一个方法,方法中显式地使用了filter,对数组进行过滤并返回
eg:
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
计算属性和观察者
computed
计算属性和Methods区别:
计算属性是基于它们的依赖进行缓存的。
只在相关依赖发生改变时它们才会重新求值。
这就意味着只要 message 还没有发生改变,
多次访问 reversedMessage 计算属性会立即
返回之前的计算结果,而不必再次执行函数。
表单输入绑定: 双向数据绑定(用在表单输入)
v-model
eg:
<input v-model="message">
<p>Message is: {{ message }}</p>
修饰符:
.lazy 当输入完成后,在model中才显示
.number 自动将Str -> number
.trim 删除左右空额
eg:
<input v-model.lazy="message">
绑定HTML Class
v-bind:class
eg:
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
data: {
isActive: true,
hasError: false
}
v-bind:class="[activeClass, errorClass]"
v-bind:class="[isActive ? activeClass : '', errorClass]"
v-bind:class="[{ active: isActive }, errorClass]" //与上面的相同
绑定内联样式: v-bind:style
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
##单文件组件: component
1.三个部分组成
1.Template
只能存在一个根元素
2.Script
3.Style
Scoped: 样式只在当前组件内生效 (npm)
2.子父组件交互(通信)
父 -> 子: props
例子:静态数值
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<blog-post post-title="hello!"></blog-post>
数组:
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
使用v-bind进行动态赋值:
<blog-post v-bind:title="postTitle"></blog-post>
data : {
postTitle : 'this is test!!';
}
Prop验证: 数据类型验证、多数据类型验证、必选项、默认值、obj,arr数据类型的默认值
props: {
// 基础的类型检查 (`null` 匹配任何类型)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
,
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
子 -> 父: emit Event
3.插槽 父给子传组件,子父都可以渲染插槽内的组件
eg:
<slota> th is the parent</slota> //父中用子组件,并在子组件中定义自定义内容
<div class="slota"> //子组件定义 <slot>注解,父组件自定义内容在此显示
this is the child
<slot></slot>
</div>
具名插槽:当有多个插槽时,父类自定义内容需要传入不同的插槽内,就需要具名插槽
<slota> //父组件引用子组件
<p slot="slot-a"> this is insert into slot-a</p>
<p slot="slot-b"> this is insert into slot-b</p>
</slota>
<div class="slota"> //自定义子组件
this is child
<slot name="slot-a"></slot>
----------------------------
<slot name="slot-b"></slot>
</div>
作用域插槽:子给父传递数据,展示效果由父来决定
<p slot="slot-b" slot-scope="cope"> {{scope.text}}</p> //父引用 //slot-scope从子组件获取数据
<slot name="slot-b" text="儿子数据"></slot> //自定义 //text定义子要传递给父的内容
动态组件:keep-alive
组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题,就需要使用到keep-alive
当不是实时更新的的组件的话,可以使用缓存,像table动态获取,表单动态提交,就不能使用缓存
<keep-alive>{{comp_view}}</keep-alive>
<button @click="changeView">切换组件</button>
import comp1 from './components/comp1';
import comp2 from './components/comp2';
export default {
name: 'App',
components: {
comp1,
comp2
},
data () {
return {
comp_view: "comp1"
}
},
methods:{
changeView() {
if (this.comp_view == 'comp1'){
this.comp_view = "comp2";
} else{
this.comp_view = "comp1";
}
}
}
}
###css过度与动画 定义<transition> name属性,并将动画的进出的css名为:.name-enter{}
在CSS过渡和动画中自动应用 class
过渡类名:
v-enter: 进入开始
v-enter-active:执行过程中
v-enter-to:结束动画
v-leave:离开开始
v-leave-active:执行过程中
v-leave-to:结束动画
eg:
<button @click="show = !show">
Toggle render
</button>
<transition name="slide-fade">
<p v-if="show">hello</p>
</transition>
.slide-fade-enter, .slide-fade-leave-to
{
transform: translateX(10px);
opacity: 0;
}
使用动画: 可以使用reverse,进行将动画反向操作
<transition name="bounce">
<p v-if="show"> this is the xichuan test</p>
</transition>
.bounce-leave-active{
animation:bounce-in 3s ease reverse ;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
自定义过渡的类名 : 使用第三方库: animate.css
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<transition name="xichuan" enter-active-class="animated flipX" leave-active-class="animated flipY">
<p v-if="show">this is the xichuan test two!!!!!!</p>
</transition>
###自定义指令 directive
全局指令:
<input v-focus>
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
局部指令:
export default {
name: 'App',
data () {
return {
show : true
}
},
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
}
钩子函数: 钩子函数可以传多个参数(在官网;了解)
bind:指令第一次绑定到元素时调用
inserted:被绑定元素插入父节点时调用
update:
componentUpdated:
unbind: 指令与元素解绑时调用
### 过滤器 filter
全局过滤:
{{name | lowCase}}
Vue.filter('lowCase', function (value) {
return value.toLowerCase()
})
局部过滤:
export default {
name: 'App',
data () {
return {
name : 'this is the tesT!'
}
},
filters:{
upCase : function (val) {
return val.toUpperCase();
}
}
###Axios
1.安装: npm install axios
2.引用加载:
import Axios from "axios"
Vue.prototype.$axios = Axios
3请求:
GET请求:
this.$axios.get('http://127.0.0.1/api/saying',{
params:{
ID: xichuan
}
})
.then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.log(error);
});
POST请求: url后面直接加参数
form-data: ?name=xichuan&age=20
x-www-urlencoded: {name:"xichuan",age:20}
axios接收的post请求参数的格式是form-data格式
import qs from "qs"
axios.post('/user', qs.stringify({
firstName: 'Fred',
lastName: 'Flintstone'
}))
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
4.全局设置参数:
Axios.defaults.baseURL = 'http://127.0.0.1';
Axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
5.拦截请求
import qs from 'qs'
// 添加请求拦截器
Axios.interceptors.request.use(function (config) {
if(config.method == "post"){
config.data == qs.stringify(config.data)
}
return config;
}, function (error) {
return Promise.reject(error);
});
// 添加响应拦截器
Axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
6.跨域问题
###Mock 数据模型
1.自己创建JSON文件,使用get请求形式访问数据
有点: 方便,快捷
缺点:只能存在get请求
2.项目中集成服务器,模拟各种接口
优点:模拟真实线上环境
缺点:增加开发成本
3.直接使用线上数据
优点;真实
缺点:不一定每一个项目都存在
1.安装与初始化
npm install mockjs
2.使用
import Mock from "mockjs"
Vue.prototype.Mock = Mock
var data = this.Mock.mock({
'list|1-10': [{
'id|+1': 1
}]
});
console.log(data)
####Router
1.安装
npm install vue-router
2.引用:
import VueRouter from 'vue-router'
Vue.use(VueRouter)
3.使用
const router = new VueRouter({
routes:[
{path: "/",component: HelloWorld}
]
})
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
4.视图
<router-view/>
5.跳转(导航) 相当于<a>标签,但最好不要使用<a>标签
<router-link>
<router-link to="/">Go to Foo</router-link>
6.路由嵌套
在父父中定义组件
const router = new VueRouter({
routes:[
{path: "/",component: HelloWorld},
{
path:"/helloVue",
component:HelloVue,
children:[
{path: "child1",component: Child1}, //这里的child1使用的是名称,并不是相对路径
{path: "child2",component: Child2}
]
}
]
})
在父父页面显示父组件
<div id="app">
<router-link to="/">hello1</router-link>
<router-link to="/helloVue">hello2</router-link>
<router-view/>
</div>
在父组件显示子组件
<div class="helloVue">
this is the test helloVue
<router-link to="/helloVue/child1">chld1</router-link> //这里to使用的是相对路径
<router-link to="/helloVue/child2">child2</router-link>
<router-view></router-view>
</div>
7.路由传递参数
const router = new VueRouter({
routes:[
{name:"helloWorld",path: "/hello/:count",component: HelloWorld} //传递参数,必须加上name这个字段,且参数名:count形式
]});
<router-link :to="'/content/'+i.id"></router-link> //这个写法也可以
<router-link :to="{name:'helloWorld',params:{count:200}}">hello1</router-link> //router-link中要改为 :to,且参数为json格式
在子元素中展示数据:
{{$route.params.count}}
8.路由高亮效果
1.在index.js 中, 添加 路由选中class名
默认是 router-link-active, 更改
const router = new VueRouter({
mode: "history", //
linkActiveClass: "active", //将router-link-active名字改为active
routes:[
{name:"helloWorld",path: "/hello/:count",component: HelloWorld} //传递参数,必须加上name这个字段,且参数名:count形式
]});
2.在全局中配置, css 样式
.active {
color: red
}
3.对于匹配 / 的, 会始终显示高亮, 需要添加 exact 属性;
<li><router-link :to="index" exact>首页</router-link></li>
###Element-UI
1.安装:
npm i element-ui -S
2.安装按需加载依赖
npm install babel-plugin-component -D
3.修改 .babelrc文件
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
### VueX
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,
并以相应的规则保证状态以一种可预测的方式发生变化
1.什么时候使用Vuex?
虽然 Vuex 可以帮助我们管理共享状态,
但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。
确实是如此——如果您的应用够简单,您最好不要使用 Vuex。
一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,
您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
2.Vuex状态管理
View -> (dispatch) Action ->(Commit) Mutations ->(Mustate)Sate -> View
注意:Action不是必需品,如果有异步操作才能用到Action,否则可以不使用
3.Actions:
Action 提交的是mutation,而不是直接变更状态。
Action 可以包含任意异步操作。 当前本地操作,使用Mutations,有异步操作使用Action
1.index.js
// vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{ //定义公共变量的地方
count: 5
},
// 更改store的状态
mutations: {
increment (state) {
state.count++
},
decrement (state) {
state.count--
}
},
// 有异步的时候, 需要action
actions: {
increment(context) {
context.commit('increment')
},
decrement (context) {
setTimeout(function () {
context.commit("decrement")
}, 10)
}
},
// 通过getter 进行数据获取
getters: {
getState(state) {
return state.count > 0 ? state.count : 0;
}
}
})
export default store
2.在main方法中引用
import store from './index'
new Vue({
el: '#app',
store,
components: { App },
template: '<App/>'
})
3.引用
<div>
获取值 --
{{ getCount }} <br/>
<button @click="add">inc</button>
<button @click="des">decri</button>
</div>
computed: {
// 避免编程负数, 需要通过方法进行获取
getCount() {
// return this.$store.state.count
return this.$store.getters.getState;
}
},
methods: {
add() {
this.$store.commit("increment")
},
des() {
// 使用 action中的异步方法
this.$store.dispatch("decrement")
}
}
##iView
1.安装
npm install iview --save
2.按需引用·
npm install babel-plugin-import --save-dev
// .babelrc
{
"plugins": [["import", {
"libraryName": "iview",
"libraryDirectory": "src/components"
}]]
}
//main.js
import { Button, Table } from 'iview';
Vue.component('Button', Button);
Vue.component('Table', Table);
github上有更多的笔记:Raray-chuan (兮川) · GitHub