前段时间学习了Vue框架,因此在我学习过程中整理了一些关于Vue的一些需要注意的地方,在后面根据所开发的项目,我可能会持续更新这篇基于Vue的博客,欢迎交流
文章目录
1.Vue中的mvvm
我们使用过Vue的人后都会清楚Vue是一种使用mvvm模式开发的框架,但是它的具体体现在哪里呢。
如上图所示:
View层:就是我们常说的视图层,也就时我们的BOM。主要用于给用户展示数据
Model层:数据层,可能是我们给定的死数据,但在开发中大概率是从服务器端请求的数据
View-model层:视图模型层,是View和Model沟通的桥梁。它主要实现了数据的绑定和数据的动态监听,实现了响应式数据化。
2. methods和computed
在vue的options选项中,除了method方法可以处理我们的逻辑以外,计算属性也是可以操作相同的事情的,似乎他们很相似,其实他们是有区别的。所以这两个方式有什么区别呢。
- 计算属性不需要使用调用的形式的写法,而methods方法必须使用
方法()
调用的形式 - 计算属性依赖data中的变化,如果data并没有发生变化,则计算属性则会取缓存结果,也就是说计算属性具有缓存功能。
- method方法不论data中的值改不改变,都会重新调用。也就是调用多少次就实现多少次,因此比较浪费效率
3. v-on的参数传递问题与常用的修饰符
v-on经常用来处理一些事件监听的操作。它的语法糖是@事件
3.1 参数传递问题
我们在使用v-on来处理事件时经常在事件中嵌入方法。这时会分三种情况。
- 不传参时,可以不带可以不带括号,但是在方法实现时可加一个参数来表示当 前event。
<div class="box">
<button @click='btnclivk'></button>
</div>
btnclivk(e){
console.log(e);//当前event对象
}
- 传普通参数时,就像通常使用函数一样,但是需要注意的是,这里的参数要么是基本数据类型,要么就必须是data中的变量
- 在传普通参数时还需要event参数,这时传入
$event
()固定写法来表示当前event对象
3.2 常用修饰符
- v-on:事件.stop:阻止事件冒泡
- v-on:事件.prevent:阻止默认行为
- v-on:事件.{keycode}:等待指定键位触发
- v-on:事件.once:只触发一次
- v-on:事件.native:监听组件跟元素的原生
5.v-if和v-show的区别
首先我们应该清楚v-if和v-show都是用来处理dom是否显示出来的操作,因此我们在这里需要清楚他们有什么不同之处。
**v-if:**在使用v-if时通常时需要创建dom的,也就是说当值为false时,删除dom,当值为true时创建dom
**v-show:**在使用时通常时使用display:none的css样式来处理是否可见的
使用常见:
当在界面中需要重复显示和隐藏的操作时我们通常需要使用v-if,因为这样更见的节省效率。
当只有一次切换时我么通常选择v-if来进行操作。
6.v-for时绑定key与不绑定key的区别
首先想象一个场景,我们要将一个数组显示在li标签上,这时会使用到v-for来对li标签进行操作。但是当我有一个需求:你需要在数组中间插入一个内容应该如何操作。
这时我们可能想着直接将内容插入数组即可。但是你是否考虑到一个问题。在Vue的底层时如何实现的。
实际上Vue底层会使用虚拟DOM来实现这个操作,但是当我们插入在中间时,可能会出现以下这种情况:
除了前面相同的dom会复用以外,剩下的所有数据都要被重新渲染。
举个例子,如果我们现在的数组是[a,b,c,d,e],当我们现在在b后面加一个f。那么默认操作是将c—>f,d—>c,e—>d,最后插入e。这样做感觉效率有所欠缺。如下图所示:
因此官方建议我们使用绑定key,key的值一般为是一个唯一标识(注意不能使用index:因为插入元素后index会改变,因此无意义)。这样一来diff算法可以找到相同的复用dom进行渲染,也就是将我们有key的li一一对应起来
最后再将我们的待插入结点插入。这样就省了不少的效率。
所以用一句话来概括,key的作用主要是为了高效的更新虚拟DOM。
7. Vue中数组方法中哪些是响应式的
我们再使用Vue时感觉其很方便的一个主要原因就是它可以响应式刷新数据。
那么再我们使用数组时,有哪些方式是数据响应式的呢。
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Vue.set()
主要:直接通过数组[下标值]是不能做到数据响应式的。
8. v-model双向绑定使用
8.1 用于表单时
v-model通常在表单中用来实现双向绑定,从而实现操作与数据实时更新,实现响应式。
也就是说当我们在表单中输入数据时,实际上数据直接就发生了更改。
lizi :
<input type="text" v-model='message'>
<p>{
{message}}</p>
以上例子就可以实现当我们输入数据时,message就实时的发生了改变,对应的p标签的内容也就发生了改变。
实际上v-model是以下两个操作的语法糖:
- v-bind为value绑定数据
- v-on:input 为表单绑定触发事件,从而为message传值。
<input type="text" :value='message' @input='message=$event.target.value'>
<p>{
{message}}</p>
其实除了在text上外,v-model还经常用在select、chacked、radio上。
修饰符:
这里主要介绍它的三个修饰符
- v-model.lazy:表示不实时更新数据,只有在用户回车时或者input失焦时才更新数据
- v-model.number:在默认情况下v-model都是一个string类型的字符串,这个修饰符可以使返回一个数字类型
- v-model.trim:去空格
9. 为什么组件中data必须是一个函数类型
首先vue的组件大多是用来复用的,那么他每复用一次,就会使用我们的data属性,如果这时我们data是一个对象时,那么当我们复用组件时则会出现一个问题,一个组件中数据变化,那么所有的组件中的数据都会变化。因此vue的底层在data属性这里添加了这个设定。
当然在开发过程中也可能会遇到这个属性,这个可以将对象暴露出去再引入,实现所有组件数据的一致性。
我们可以看一下一个很简单的例子:
写一个计数器的组件
Vue.component('mycom', {
template: '#mypom',
data() {
return {
message: 0
}
},
methods: {
add() {
this.message++
},
decre() {
this.message--
},
},
})
使用:
<div id="app">
<mycom></mycom>
<mycom></mycom>
<mycom></mycom>
<mycom></mycom>
</div>
这时我们会发现每个组件都是独立的,这时因为,这就归功于data属性是一个函数。因此他们不会共同使用一个对象内的数据。
但是如果我们有这种一个动,全部动的需求时,也很容易。
var obj={
message: 0
}
Vue.component('mycom', {
template: '#mypom',
data() {
return obj
},
methods: {
add() {
this.message++
},
decre() {
this.message--
},
},
})
这就可以实现我们想要的效果。
10.父子组件之间实现的复杂双向绑定
一个需求:现在在组件中有两个input,其中需要实现input的双向绑定(且改变父组件的data值),且输出时第二个input的值时第二个值的100倍。
用到的技术点:父子组件通信,表单的双向绑定
值得一提的是当我们Vue官方不建议使用model时直接将props的值放在里面,因为这样这里的值是从父组件传递而来,因此直接修改可能会导致紊乱。因此我们需要借助组件的data属性来做值得绑定;
至于另一个需求,改变data的属性,那么我们可以使用父传子的方法将组件的data传给父组件,再去修改父组件data的值,这样一来我们及修改了父组件的data,同时也就修改了子组件props的相关值。
最后的需求是100倍,这个也在我们的input事件触发时监听,然后计算,在通过emit传递即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<mycon :cnum1='num1' :cnum2='num2' @event1='event1' @event2='event2'></mycon>
</div>
<template id="cpm">
<div>
<p>props:{
{cnum1}}</p>
<p>data:{
{copycnum1}}</p>
<input type="text" name="" id="" :value='copycnum1' @input='docopycnum1'>
<p>props{
{cnum2}}</p>
<p>data{
{copycnum2}}</p>
<input type="text" name="" id="" :value='copycnum2' @input='docopycnum2'>
</div>
</template>
</body>
<script src="../vue.js"></script>
<script>
var cpm = {
template: '#cpm',
props: {
cnum1: Number,
cnum2: Number,
},
data() {
// 官方建议做法
return {
copycnum1: this.cnum1,
copycnum2: this.cnum2,
}
},
methods: {
docopycnum1(event) {
this.copycnum1 = event.target.value;
this.$emit('event1', this.copycnum1);
this.copycnum2=this.copycnum1*100
this.$emit('event2', this.copycnum2)
},
docopycnum2(event) {
this.copycnum2 = event.target.value;
this.$emit('event2', this.copycnum2)
this.copycnum1=this.copycnum2/100
this.$emit('event1', this.copycnum1)
}
},
}
new Vue({
el: '#app',
data: {
num1: 0,
num2: 0
},
components: {
mycon: cpm
},
methods: {
event1(data) {
this.num1 = parseFloat(data);
},
event2(data) {
this.num2 = parseFloat(data);
}
},
})
</script>
</html>
11.vue使用webpack时的注意事项
首先我们项目中需要有vue的环境。
npm安装:
npm install vue --save
安装以后,我们直接写vue相关的代码后进行编译会发现有报错:
这个错误的原因是因为vue在构建发布时有两个版本,runtime-only和runtime-compiler。
**runtime-only:**该版本不能有任何的template
**runtime-compiler:**代码里可以有template,因为有compiler可以编译template
解决方案(在webpack配置文件中加入):
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
因为这个resolve时专门来处理路径问题的,所以故名思意,我们也可以猜出来,这是改变了默认配置
11.2 编译vue文件
使用webpack中打包vue文件时,我们需要安装vue-loader插件和vue-template-compiler 插件
接着在配置文件中配置:
module: {
rules: [
{
test: /\.vue$/,
use: ['vue-loader']
}
]
},
使用之后我们会发现会报错。
报错原因大概是:vueloader不能使用,缺少一个插件。
我们可以配置一个插件(不用安装):
const VueLoaderPlugin = require('vue-loader/lib/plugin');
plugins: [
new VueLoaderPlugin(),
...
],
12.Runtime-Compiler和Runtime-Only的区别
当我们使用vue cli2来构建项目时通常会让我们选择vue的构建模式。我们创建两个项目会发现src目录下的main.js文件按有所不同
Runtime-Compiler模式:
import App from './App';
new Vue({
el: '#app',
components: {
App },
template: '<App/>',
});
Runtime-Only模式:
import App from './App';
new Vue({
el: '#app',
render:h=>h(app)
});
我们发现这两个模式在Vue实例中的写法有所不同,我们发现Runtime-Compiler模式时使用的时我们常规的注册使用组件的方式,而Runtime-only是使用render函数进行渲染,那么这两者有什么区别?
这是一张template在Vue中的渲染过程:
ast:template解析后的产物,抽象语法树
render函数:ast被编译就的产物,用于生成一个虚拟dom
virtual dom:虚拟dom
我们可以看出它大概需要这几个过程:template->ast->render函数->虚拟dom->渲染到ui
然而我们使用第二种Runtime-Only是直接在render函数的结点开始往下操作的。
结论:Runtime-Only的效率要比Runtime-Compiler运行效率高,并且源代码的量更少,打包后的体积更加轻量。
runtime-only: 将template在打包的时候,就已经编译为 render函数
runtime-compiler: 在运行的时候,才去编译 template因此我们更加推荐使用Runtime-Only模式来构建我们的项目。
关于Render函数的使用:
1.直接在render函数中给我们的回调函数传入我们的组件对象。
new Vue({
el: '#app',
// components: { App },
// template: '<App/>',
render:(e) => {
return e(App)
}
});
2.传入基本的dom:
render:(e) => {
return e('div',{
class:'box'},['web'])
}
其中第一个参数是dom元素,第二个参数是属性值,第三个为data。
13.vue-router懒加载
关于路由的懒加载,官方给我们的解释为:
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
其实就是说我们的每一个路由对应的就是一个给用户展示的页面,然而按照常规的操作这些页面最终会通过webpack打包为一个bundle.js的文件,因此就造成了这个页面十分的庞大,所在在请求的时候可能会花费一定的时间,给用户造成不好的体验。因此我们可以通过路由懒加载的方式来解决这个问题。也就是说不同的路由页面打包成不同的js文件,这样就解决了服务器耗时的问题。
在我们未使用懒加载时,打包vue项目会生成三个文件,一个是app的所有业务代码,一个是组织管理模块关系的代码,还有一个就是项目引入第三方的代码。
接着我们看一下实现懒加载的方式:有三种方式分别是结合异步组件的方式,AMD的方式,es6模块化的方式
在ES6中, 我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割.所以我们就是用最简单的方式:
component: () => import('../components/about.vue')
实例:
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/hello',
component: () =>import('../components/HelloWorld.vue')
},
{
path: '/home',
component: () => import('../components/home.vue')
},
{
path: '/about',
component: () => import('../components/about.vue')
},
{
path: '/person/:userid',
component: () => import('../components/person.vue')
}
],
我们发现每个路由界面都有一个js文件,这样一来就可以做到我们按需加载的要求,减轻了服务器的压力
转载:https://blog.csdn.net/M_Edison/article/details/115871958