一篇小小的vue2.0教程。首先,本笔记只针对于vue2.0。因为最近在学vue.js,因为准备要做项目,所以先准备系统的学习一下。此篇笔记会较为全面的记录vue中各个比较重要的知识点,我会写的比较注重代码质量和格式,希望能为其他一起学习vue的小伙伴们能带来一点帮助。
过渡动画
原生css实现过渡动画
dom结构
<div id="app">
<button @click="toggle">显示和隐藏数据</button>
<transition name="show">
<span v-show="isshow">hello vuejs</span>
</transition>
</div>
js部分
var vm = new Vue({
el: "#app",
data: {
isshow: false
},
methods: {
toggle: function () {
this.isshow = !this.isshow;
}
}
})
在vue2.0中,需要有过渡动画的元素应在该元素外层包裹`<transition></transition>`
接下来是css部分
```css
.show-enter-active,.show-leave-active {
transition: all 0.4s ease;
padding-left: 10px;
}
.show-enter,.show-leave-active {
padding-left: 100px;
}
在vue2.0中,过渡动画的css有着固定的写法,在该例子中开始和结束状态时类名为.show-enter-active
,和.show-leave-active
。开始和结束的过程的类名为.show-enter
,show-leave-active
。
Animate.css实现过渡动画
首先需要引入animate.css
<link rel="stylesheet" href="animate.css">
dom结构
<div id="app">
<button @click="toggle">显示和隐藏数据</button>
<transition enter-active-class="fadeInRight" leave-active-class="fadeOutRight">
<div v-show="isshow" class="animated show">hello vuejs</div>
</transition>
</div>
js
var vm = new Vue({
el: "#app",
data: {
isshow: false
},
methods: {
toggle: function () {
this.isshow = !this.isshow;
}
}
})
首先在vue2.0中,我们需要在<transition>
标签中定义好进场动画和出场动画的class类,属性名分别为enter-active-class
和leave-active-class
。
在这里依旧需要在产生过渡动画的元素外包裹<transition></transition>
,另外和前面不同的是,animate.css所生效的对象必须要是块级元素
,所以我们在这里将之前的<span>
换成了<div>
。
到这里,利用animate.css来完成过渡动画就已经完成了。
结合钩子函数实现过渡动画
此方法是结合vue生命周期钩子函数的思路来分别设置进场动画
、过场动画
、出场动画
三个流程,来完成单向的过渡动画效果。
dom结构
<div id="app">
<button @click="toggle">显示和隐藏数据</button>
<transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
<div v-show="isshow" class="animated show">hello vuejs</div>
</transition>
</div>
我们在需要实现效果的元素外包裹<transition>
,然后在标签中注册了三个方法,分别是enter
、enter
、after-enter
。
js
var vm = new Vue({
el: "#app",
data: {
isshow: false
},
methods: {
toggle: function () {
this.isshow = !this.isshow;
},
beforeEnter: function (el) {
el.style.transform = "translate(100px,0)";
},
enter: function (el, done) {
el.offsetWidth;
el.style.transform = "translate(10px, 0";
done();
},
afterEnter: function (el) {
this.isshow = !this.isshow;
}
}
})
随后我们需要在methods中定义这三个方法,在这里描述元素变换的过程。
.show {
transition: all 0.4s ease;
}
然后在样式中,必须要定义好该元素的过渡属性,才能实现过渡效果。
到这里,利用animate.css来完成过渡动画就已经完成了。
组件
全局注册
Vue.component('my-component-name', {
// ... 选项 ...
})
这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue)
的模板中。比如:
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。
局部注册
在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components
选项中定义你想要使用的组件:
new Vue({
el: '#app'
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
对于 components
对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。
注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA
在 ComponentB
中可用,则你需要这样写:
var ComponentA = { /* ... */ }
var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}
dom和组件的绑定
vue1.0和vue2.0的写法有点区别,在vue1.0中针对dom和组件他分别有
v-el
和v-ref
这两种指令来进行绑定,那么在2.0中认为这两种其实都是dom结构中的一部分,所以统一改为ref
来进行绑定,那么后面只详细讲vue2.0的写法,对1.0有兴趣的同学可以自行百度。
<div id="div1" ref="mydiv">hello v-el</div>
绑定元素时我们需要在标签中加上ref
指令来绑定对象,指定绑定名称之后我们可以随意的在javascript代码中来调用
我们尝试着在控制台打印出该对象
new Vue({
el: '#app',
methods:{
getdom: function(){
console.log(this.$refs.mydiv);//<div id="div1">hello v-el</div>
}
}
})
利用parcel打包vue项目
首先用npm工具安装parcel
npm i -g parcel-bundler
执行命令(生产环境):
设置环境变量: parcel build index.html NODE_ENV=production
设置输出目录: parcel build index.html -d build/output
设置要提供服务的公共 URL: parcel build index.html --public-url ./
禁用压缩: parcel build index.html --no-minify
禁用文件系统缓存: parcel build index.html --no-cache
如果提示babel没有安装,就根据报错的提示进行npm 安装babel
最后,在package.json
中添加(vue官方文档中的安装部分也有说明)
{
// ...
"alias": {
"vue" : "./node_modules/vue/dist/vue.common.js"
}
}
更详细的教程:点击我:parcel与vue
export default 和 data(){ return {} } 的两个问题
(已经找到解答)
1)首先就是.vue结尾的文件为何需要export default,就像下面的代码一样?
2)为什么data需要return,我不用return,直接 data(){
menu:MENU.data,
poi:POILIST.data
}不行吗?
<script>
import { POILIST, MENU } from '../config/vuex.js';
export default {
data() {
return {
menu: MENU.data,
poi: POILIST.data
}
},
methods: {
set() {
MENU.list.push('首页');
POILIST.list.push({
lng: 124.1,
lat: 42.3
});
}
}
}
</script>
- export default是ES6的语法,意思是将这个东西导出,你要import 引入东西,导出了才能引用。
-
data是一个函数是因为data是被很多组件共享的,如果 data 是一个的对象的话,每次实例化会造成所有的实例共享引用同一个数据对象,如下
var fnc= function() {}
fnc.prototype.data = {
a: 1,
b: 2,
}
var fnc1 = new fnc()
var fnc2 = new fnc()
fnc1.data.a === fnc2.data.a // true
fnc2.data.b = 1;
fnc2.data.b // ==1
data 是函数的话,每次创建一个新实例后,调用 data 函数,用return返回初始数据的一个全新副本数据对象,就避免了所有实例共享引用同一个数据对象。
ES6笔记
因为学vue的过程中发现里面有着许多es6的知识,如果没有系统全面的掌握es6,学起来是非常吃力的,所以决定中途先把es6好好补一下,然后继续学习vue。
let
看了MDN的文档,我得到的信息有这么几条:
1. let 声明的变量的作用域是块级的;
2. let 不能重复声明已存在的变量;
3. let 有暂时死区,不会被提升。
4. let 的「创建」过程被提升了,但是初始化没有提升。
5. var 的「创建」和「初始化」都被提升了。
6. function 的「创建」「初始化」和「赋值」都被提升了。
var liList = document.querySelectorAll('li') // 共5个li
for( let i=0; i<liList.length; i++){
liList[i].onclick = function(){
console.log(i)
}
}
另外,for
循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
const
const
声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const
只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
字符串方法
1. includes()
2. startsWidth()
3. endsWidth()
4. repeat()
5. padStart()
6. padEnd()
7. 模版字符串``
数组方法
1. set()
2. add()
3. delete()
4. has()
5. clear()
数值方法
1. Number.isFinite() //判断数值是否有限
2. Number.isNaN() //判断数值是否为NaN
3. Number.parseInt() //将数值转换为Int
4. Number.parseFloat() //将数值转换为浮点数
5. Number.isInteger() //判断数值是否为整数
6. Number.EPSILON //ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。
7. Number.isSafeInteger() //判断数值是否为安全整数 区间为-2^53到2^53之间(不含两个端点)
8. Math.trunc() //扩展方法,去掉小数部分
9. Math.sign() //来判断Math.sign方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
它会返回五种值。
参数为正数,返回+1;
参数为负数,返回-1;
参数为 0,返回0;
参数为-0,返回-0;
其他值,返回NaN。
10. Math.cbrt() //Math.cbrt方法用于计算一个数的立方根。
函数方法
1. 函数参数默认值 //参数可直接设置默认值,若未传参时,参数等于预设的默认值
2. rest 参数 // ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
3. 严格模式 // 从 ES5 开始,函数内部可以设定为严格模式。ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
4. name 属性 //函数的name属性,返回该函数的函数名。、
function foo() {}
foo.name // "foo"
5. 箭头函数 //ES6 允许使用“箭头”(=>)定义函数。
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
5.1 嵌套的箭头函数 //箭头函数内部,还可以再使用箭头函数。下面是一个 ES5 语法的多重嵌套函数。
6. 双冒号运算符 //箭头函数可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。但是,箭头函数并不适用于所有场合,所以现在有一个提案,提出了“函数绑定”(function bind)运算符,用来取代call、apply、bind调用。
7. 尾调用优化 //尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。
8. 尾递归 //函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
9. 函数参数的尾逗号 //ES2017 允许函数的最后一个参数有尾逗号(trailing comma)。此前,函数定义和调用时,都不允许最后一个参数后面出现逗号。
props
父组件与子组件如何传值?
首先我们列举两个文件,父组件:todo.vue
,子组件:item.vue
。
那么在父组件中,我们必然看到父组件调用了子组件,以下为父组件todo.vue
中的部分代码:(已删除无关代码)
<template>
<section class="real-app">
<Item :todo="todo"
v-for="todo in todos"
:key="todo.id"
@del="deleteTodo"></Item>
</section>
</template>
<script>
import Item from './item.vue'
export default {
data() {
return {
todos: [],
filter: 'all'
}
},
components: {
Item
},
methods: {
addTodo(e) {
this.todos.unshift({
id: id++,
content: e.target.value.trim(),
completed: false
})
e.target.value = ''
},
deleteTodo() {
return true
}
}
}
</script>
我们可以看到在父组件中定义了一个<Item></Item>
标签中我们用v-for
循环出了todo
对象,并在标签上用:todo="todo"
将todo对象进行传入。
由于业务需要我们必须要将值传入item.vue
中进行判断。
这时,我们便可以用到props方法
,那究竟怎么用呢?talk is cheap,来人给客官上代码!以下为子组件item.vue
中的部分代码:
<template>
<div :class="['todo-item', todo.completed ? 'completed' : '']">
<input type="checkbox"
class="toggle"
v-model="todo.completed">
<label>{{todo.content}}</label>
</div>
</template>
<script>
export default {
props: {
todo: {
type: Object,
required: true
}
}
}
</script>
这里,我们在js中用props
方法将父组件的todo
传了进来,类型为Object,而且不能为空。现在我们就可以在上面尽情的用todo对象啦。
emmit
在子组件触发了click事件时我们需要修改父组件的值,那么我们该如何做?
方法有很多,比如我们在父组件中定义了一个方法,随后用props传进来,然后在子组件中调用。那么,目前来说,更流行的方法为emmit,我们根据实际代码来讲。以下为子组件item.vue
中的部分代码:
<template>
<div>
<button class="destory"
v-bind:click="deleteTodo"></button>
</div>
</template>
<script>
export default {
props: {
todo: {
type: Object,
required: true
}
},
methods: {
deleteTodo() {
this.$emit('del', this.todo.id)
}
}
}
</script>
我们在子组件中用@click
绑定了一个方法,在方法中,我们用emit
注册了del,并传出一个this.todo.id
那么我们在父组件中,便可以在标签中通过@del=""
或者v-on:del=""
来监听到这里传出的值。以下为父组件todo.vue
中的部分代码
<template>
<section class="real-app">
<Item :todo="todo"
v-for="todo in todos"
:key="todo.id"
@del="deleteTodo"></Item>
</section>
</template>
<script>
import Item from './item.vue'
export default {
data() {
return {
todos: [],
filter: 'all'
}
},
components: {
Item,
},
methods: {
deleteTodo(id) {
// 通过参数接收将子组件传出的值
return true
}
}
}
</script>
Vuex
初使用Vuex有感,首先npm i vuex -D
完成Vuex的安装。
然后我们在src中的目录结构为
src
├─store
│ │ index.js
│ │
│ ├─getters
│ │ index.js
│ │
│ ├─mutations
│ │ index.js
│ │
│ └─state
│ index.js
为了方便日后的维护和统一修改,我将getter
、mutations
、state
等相关的配置全都放到单独的文件夹中。
在store/index.js
文件中,我们的项目如果使用的是服务端渲染,那么我们需要注意的是在我们最后将store对象传出时,为了防止内存溢出,我们注意的是不能直接传出store
,而是用箭头函数的形式传出。相关代码:
export default () => {
return new Vuex.Store({
state: defaultState,
mutations,
getters
})
}
我们有两种方法可以在app.vue
中调用vuex。(第一种更优)
computed: {
// 第一种
// ...mapState(['count']),
// 第二种
// ...mapState({
// count: 'count'
// }),
// 第三种
...mapState({
count: (state) => state.count
}),
// 第四种
// count() {
// return this.$store.state.count
// },
fullName() {
return this.$store.getters.fullName
}
}
以及如何更优雅的在app.vue
中去调用actions
和mutations
。(方法二更优)代码:
mounted() {
// console.log(this.$store)
let i = 1
setInterval(() => {
// mutations方法一
// this.$store.commit('updateCount', i++)
// mutations方法二
this.updateCount(i++)
}, 1000)
// actions方法一
// this.$store.dispatch('updateCountAsync', {
// actions方法二
this.updateCountAsync({
num: 5,
time: 2000
})
},
methods: {
// 此处为方法二进行注册
...mapActions(['updateCountAsync']),
...mapMutations(['updateCount'])
},
Vue-router 底部导航栏 一级路由显示 子路由不显示
最近碰到了vue-router切换时底部导航在手机端会被拖拽导致显示的问题,查询后发现了vue-router中meta中的属性可以直接绑定到模板中的v-if中
talk is cheap,上代码
router/index.js
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/first', component: firstView, meta: { navShow: true, cname: '一级页面' }, name: 'first' },
{ path: '/sub', component: subView, meta: { navShow: false, cname: '子页面' }, name: 'sub' },
],
});
src/app.vue
<Bar v-show="$route.meta.navShow">
…………………
…………………
xxxx – 剩下内容待填坑中