vue:渐进式javascript框架;框架是提供基础性服务;库主要提供一些api,现在两者区别越来越小。
Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data
选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty
把这些 property 全部转为 getter/setter。在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。 Vue 不允许动态添加根级响应式 property,所以你必须在初始化实例前声明所有根级响应式 property,哪怕只是一个空值。
文档地址:https://cn.vuejs.org/v2/guide/
Vue.use()是全局注册插件 ,Vue.component()是全局注册组件。
@符号:在vue项目中 @ 符号代表的是根目录,即 src 目录。在 bulid/webpack.base.conf.js 文件中修改相关配置,
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'), //这里的@ 就代替了src
}
},
Vue 是通过 webpack 实现的模块化,因此可以使用 import 来引入模块。
export 用来导出模块,Vue 的单文件组件通常需要导出一个对象,这个对象是 Vue 实例的选项对象,以便于在其它地方可以使用 import 引入。而 new Vue() 相当于一个构造函数,在入口文件 main.js 构造根组件的同时,如果根组件还包含其它子组件,那么 Vue 会通过引入的选项对象构造其对应的 Vue 实例,最终形成一棵组件树。
export 可以导出多个命名模块,导入的时候要用大括号括起来,import { str, f } from 'demo1';
export default 只能导出一个默认模块,这个模块可以匿名,引入的时候可以给这个模块取任意名字,例如 "obj",且不需要用大括号括起来,import obj from 'demo1'。
el:元素的挂载位置,可以是css选择器、dom元素。
data:模型数据,值时一个对象。
前端渲染的方法:原生js字符串拼接,然后用dom插入。前端模版引擎。vue模版。
***插值表达式
插值表达式:{{ }};支持基本的运算。
***动态属性,版本2.6开始
可以用方括号括起来的 JavaScript 表达式作为一个指令的参数,
<a v-bind:[attributeName]="url"> ... </a>
attributeName是动态的,动态参数预期会求出一个字符串,异常情况下值为 null
。这个特殊的 null
值可以被显性地用于移除绑定。
***指令
指令的本质就是自定义属性;格式以v-开始;
插值表达式存在闪动的问题,v-cloak:先隐藏,替换好值之后再显示最终的值。
v-text:插入文本
v-html:插入标签,有风险,一般不要跨域使用。
v-pre:填充原始信息
***双向数据绑定:
v-model:用户修改数据会影响到模型中的数据。
v-model的本质就是绑定事件结合绑定属性。
Model:模型数据, view:视图,dom元素;view-model:控制逻辑。
v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定。它负责监听用户的输入事件以更新数据(它对应的是输入的数据或者选择的数据)。v-model
会忽略所有表单元素的 value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data
选项中声明初始值。
v-model
在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用
value
property 和input
事件; - checkbox 和 radio 使用
checked
property 和change
事件; - select 字段将
value
作为 prop 并将change
作为事件。
数据绑定中的修饰符:
.lazy 在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy
修饰符,从而转为在 change
事件_之后_进行同步:
<input v-model.lazy="msg">
.number
自动将用户的输入值转为数值类型,<input v-model.number="age" type="number">
.trim
自动过滤用户输入的首尾空白字符 ,<input v-model.trim="msg">
***事件绑定
v-on:click=""
简写@click="add(1,2,$event)"带参数,最后一个是事件对象,
methods:{
add:function(a,a1,event){
三个参数是传递的值。
};
add1:function(event){如果事件直接绑定函数名,传递的事件对象默认作为函数的第一个参数。
}
}
事件修饰符:
v-on:click.stop=""阻止冒泡
v-on:click.prevent=""阻止默认行为
按键事件修饰符:v-on:keyup.enter=""用键盘的enter键出发事件
v-on:keyup.delete=""用键盘的delete键出发事件
可以自定义按钮修饰符:Vue.config.keyCodes.名字(随便起)=112(这个数字是键盘上的键盘码keyCode)
<!-- 完整语法 --> <a v-on:click="doSomething">...</a>
<!-- 缩写 --> <a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) --> <a @[event]="doSomething"> ... </a>
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a><!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form><!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a><!-- 只有修饰符 -->
<form v-on:submit.prevent></form><!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div><!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div><!-- 点击事件将只会触发一次 --> <a v-on:click.once="doThis"></a>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self
会阻止所有的点击,而 v-on:click.self.prevent
只会阻止对元素自身的点击。
.left
.right
.middle
.exact
修饰符允许你控制由精确的系统修饰符组合触发的事件。
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta
***属性绑定
v-bind:href="这里放data中的数据,动态的设置属性值"
:href=""和上面的是同一个意思。
<a :[key]="url"> ... </a>动态参数缩写
***样式绑定
v-bind:class="{样式:控制数据,样式:控制数据}"
data: { isActive: true, hasError: false }
v-bind:class="{ active: isActive, 'text-danger': hasError }" // isActive和hasError控制样式是否起作用
v-bind:class=''styleObject" //styleObject是一个包含样式的对象
data: { activeClass: 'active', errorClass: 'text-danger' }
v-bind:class="[activeClass,errorClass]" //样式列表
v-bind:style="{样式:样式值 }" 内联样式
v-bind:style="styleObject对象 " 内联样式
data: { styleObject: { color: 'red', fontSize: '13px' } }
v-bindclass可以和普通的class选择器一起使用,
***分支循环结构
分支:v-if(是否渲染到页面)
v-else
v-else-if 多个判断
v-show:单独控制是否显示。(已经渲染到了页面,如果一个元素频繁显示和隐藏,就用这个)
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
循环:v-for="item in list" 元素item、list数组
v-for="(item,index) in list" index是元素索引。
:key='item.index' v-for='(item,index) in list' 加上 :key可以提高性能。
遍历对象:v-for='(value,key,index) in obj' 值、键、索引(value、key、index名字可以自己起)
v-for可以使用值范围:in后面直接跟一个整数,整数表示的范围为1到整数值。
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
当它们处于同一节点,v-for
的优先级比 v-if
更高,这意味着 v-if
将分别重复运行于每个 v-for
循环中。
***数组更新检测
数组的变更方法,也就是会变更调用了这些方法的原始数组。原始数组会改变。
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
非变更方法,原始数组不会改变,它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:
例如filter()
、concat()
、slice()
numbers: [ 1, 2, 3, 4, 5 ]
numbers.filter(function (number) {
return number % 2 === 0
})
***Vue常用特性
表单修饰符:v-model.number="age"吧默认值转换为数值;
v-model.trim=" fd "去掉开始和结尾的空格
v-model.lazy="msg" 将input事件切换成change事件(change事件是失去焦点的时候才触发)。
自定义指令:Vue.directive('指令名称focus',{
inserted:function(参数el,参数bindding){
//el表示指令绑定的元素,el.focus();
//bidding中可以获取到参数的值
}
});
使用的时候要写成这样:v-focus;
计算属性:把模版中复杂的表达式操作抽离出来,使用的时候在差值表达式中直接使用{{reverseString()}}获取reverseString方法的返回值。
computed:{
reverseString:function(){
reuturn this.msg.split("")
}}
计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
计算属性是基于依赖(data中的数据)缓存的,methods中的方法每次都重新执行。
侦听器:msg是data中的数据,有变动就会触发
watch:{
msg:function(val){
val就是msg的最新值,只要有变动,这里就能监听到
}
}
过滤器:作用是格式化数据;
Vue.filter("过滤器名称",function(value){
return val.charAt(0).toUpperCase()+val.slice(1);具体要处理的过程
})
局部顾虑器:filters:{
"过滤器名称":function(value){
return val.charAt(0).toUpperCase()+val.slice(1);具体要处理的过程
}
}
带参数的过滤器:value就是过滤器传递过来原来的值,从第二个参数开始就是过滤器携带的参数,可以有很多个,
{{msg | 过滤器名称(参数1,参数2) }}下面的arg1对应的就是参数1,arg2对应的就是参数2;
Vue.filter("过滤器名称",function(value,arg1,arg2){
return val.charAt(0).toUpperCase()+val.slice(1);具体要处理的过程
})
过滤器使用:{{msg | 过滤器名称 }}可以跟多个过滤器,级联操作。
绑定属性的时候也可以使用过滤器,:abc="msg |过滤器"
生命周期:挂载:初始化相关属性;更新:;销毁:;
变异数组(原来的数组会改变)、替换数组(会形成一个新的数组,原来的数组内容不变)。
数组响应式变化:Vue.set(要处理的数组,索引,值);
vm.$set(要处理的数组,索引,值);
mounted:{ }该生命周期函数被触发的时候,模板已经可以使用过,此时一般用于获取后台数据,填充到模板。
***组件化
规范:Web Components
组件是可复用的 Vue 实例,它们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。
公用的组件放置在 components 目录下,项目组件新建 views 目录来存放。
自定义组件中的data必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。
如果作为路由的页面,必须在index.js 中注册;如果仅仅作为外部组件引用的话,不需要再index.js中注册。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。
全局组件注册:它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue
) 的模板中。所有实例都能用全局组件。注意:全局组件必须写在Vue实例创建之前,才在该根元素下面生效。一般在main.js中new Vue之前注册;(全局注册的行为必须在根 Vue 实例 (通过 new Vue
) 创建之前发生)
mian.js
Vue.component(“组件名称”,{
data:function(){
return {
msg:0
}
},
template:组件模板内容'<button @click="">点击{{msg}}</button>',
methods:{
handle:function(){
}
}
}
)
data必须是一个函数,组件模板内容必须是单个根元素,最外层不能有兄弟元素。
组件模板内容可以是模板字符串(需要es6提供支持);
如果使用驼峰式命名组件,只能在字符串模板中使用驼峰式,但是在普通标签模板中可以使用短横线的方式(首字母都是小写,中间用短横线隔开)。
局部组件注册:可以在实例选项中注册局部组件,这样组件只能在这个实例中使用;
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用这个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
定义组件var componentA={ template: '<div><h1>自定义组件02</h1><slot></slot></div>' }
在
components
选项中定义你想要使用的组件:new Vue{
el: '#app', //vue挂载到id为app的元素上
components:{
hello-world:componentA
}
}
局部组件只能在当前的父组件中使用。
<template>
<div>
<h1>{{ msg }}</h1>
<my-com>使用局部组件</my-com>
</div>
</template>
<script>
// export default{
// data(){
// return {
// msg:"home自定义局部组件"
// }
// },
// 自定义局部组件
// components:{
// myCom:{ //组件的名字使用驼峰命名,使用的时候就要使用横线连接
// template:"<h1>自定义组件01</h1>"
// }
// }
// }
// }
//自定义局部组件
var autocom = {
template: '<div><h1>自定义组件02</h1><slot></slot></div>'
}
export default{
data(){
return {
msg:"home自定义局部组件"
}
},
components:{
prop:["title"],//相当于属性
'myCom':autocom //自定义局部组件
}
}
</script>
外部组件更加灵活,并且具有全局性,可以全局复用。
将原生事件绑定到组件
在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on
的 .native
修饰符:
<base-input v-on:focus.native="onFocus"></base-input>
Vue 提供了一个 $listeners
property,它是一个对象,里面包含了作用在这个组件上的所有监听器。
.sync
修饰符:可以用来父子组件的双向更新,具体查看官方文档。
Vue调试工具用法:Devtools;要安装到chrome的扩展中。
组件间数据交互:
任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要使用 prop。
父组件通过 Prop向子组件传递:父组件中:<自定义组件 :父组件属性=“data中的数据”>,子组件中的props:["父组件的属性"]中获取;如果在props中使用驼峰形式,模板中需要使用短横线。
props支持的数据类型:Strings、number、boolen、数组、对象
Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。为了给博文组件传递一个标题,我们可以用一个 props
选项将其包含在该组件可接受的 prop 列表中:
以字符串的形式列出:props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
以对象的形式列出:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})一个 prop 被注册之后,你就可以像这样把数据作为一个自定义 attribute 传递进来:
静态赋值:<blog-post title="My journey with Vue"></blog-post>
动态赋值:<!-- 动态赋予一个变量的值 --> <blog-post v-bind:title="post.title"></blog-post>
如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind
(取代 v-bind:prop-name
):
post: {
id: 1,
title: 'My Journey with Vue'
}
下面的模板:这个v-bind后面没有prop
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post
v-bind:id="post.id"
v-bind:title="post.title"
></blog-post>
子组件向父组件:props传递数据是单向的,只允许父组件向子组件传递,不允许子组件中操作父组件的数据。
通过自定义事件向父组件传值:在子组件中@click='$emit("事件名称",参数)',也可以在方法中触发,this.$emit("事件名称",参数);在父组件中监听:@事件名称=“方法名($event)”,$event接收子组件传递的参数;@和v-on:等价。
兄弟组件传值:事件中心管理组件间的通信;
事件中心var eventH=new Vue();这一步一般是用一个js文件表示,然后在兄弟组件中引入js文件。js文件中 import Vue from 'vue' export default new Vue()
事件监听evenH.$on('事件名称',方法),evenH.$on('one-even',(val)=>{ }),这个事件放在生命周期函数中mounted;
evenH.$off('事件名称');
事件触发evenH.$emit('事件名称',参数);
自定义组件中使用v-model
input组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。
main.js中注册全局组件
Vue.component('my-component', {
template: `
<p>
<input
ref="input"
v-bind:value="value"
@input="$emit('input', $event.target.value)"
>
</p>
`,
props: ['value'], // 名为 value 的 prop
})
xx.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<BUTTON v-on:click="changemsg">改变msg</BUTTON>
<my-component v-on:input="mycomponentchange" v-model="msg"></my-component>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome'
}
},
methods:{
mycomponentchange:function(res){
console.log("新值"+res)
},
changemsg:function(){
this.msg="newmsg"
}
}
}
</script>
model 选项可以指定当前的事件类型和传入的 props。
main.js中注册全局组件
Vue.component('my-component', {
model: {
prop: 'value',
event: 'change' // onchange 事件
},
props: ['value'],// 名为 value 的 prop
template: `
<p>
<input
ref="input"
v-bind:value="value"
@change="$emit('change', $event.target.value)"
>
</p>
`
})
xx.js
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<BUTTON v-on:click="changemsg">改变msg</BUTTON>
<my-component v-on:change="mycomponentchange" v-model="msg"></my-component>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome'
}
},
methods:{
mycomponentchange:function(res){
console.log("新值"+res+" "+this.msg)
},
changemsg:function(){
this.msg="newmsg"
}
}
}
</script>
v-model中的msg的值会传入全局组件my-component中的prop: 'value';当在input中输入值时,按回车就会触发@change事件( @change="$emit('change', $event.target.value)",发出的事件是change,发出的数据为当前input框的值$event.target.value),在父组件中是用v-on:change来接收全局组件中发出的事件。
动态组件
<!-- 使用保留的 <component> 元素,动态地绑定到它的 v-bind:is 特性,可以实现动态组件 ,让多个组件使用同一个挂载点,并动态切换,这就是动态组件-->
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition>
相似,<keep-alive>
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。当添加:max属性的时候,一旦这个数字达到了最大值,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉。
当组件在 <keep-alive>
内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行。
通过 ref
这个 attribute 为子组件赋予一个 ID 引用(<base-input ref="usernameInput"></base-input>),在使用的时候 this.$refs.usernameInput;当 ref
和 v-for
一起使用的时候,你得到的 ref 将会是一个包含了对应数据源的这些子组件的数组。
<template>
<div id="example">
<button @click="change">第一个页面</button>
<button @click="change2">第二个页面</button>
<button @click="change3">第三个页面</button>
<!-- 使用保留的 <component> 元素,动态地绑定到它的 v-bind:is 特性,可以实现动态组件 ,让多个组件使用同一个挂载点,并动态切换,这就是动态组件-->
<component v-bind:is="currentView"></component>
</div>
</template>
<script>
var home = {template:'<div>我是第一页</div>'};
var post = {template:'<div>我是第二页</div>'};
var archive = {template:'<div>我是第三页</div>'};
export default {
data(){
return {
index:0,
arr:['home','post','archive']
}
},
components: {
home,
post,
archive
},
computed:{
//这个返回的是一个组件,v-bind:is指向的是一个组件
currentView(){
return this.arr[this.index];
}
},
methods:{
change(){
// this.index = (++this.index)%3;
this.index=0;
},
change2(){
this.index=1;
// this.index = (++this.index)%3;
},
change3(){
this.index=2;
// this.index = (++this.index)%3;
}
}
}
</script>
异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
边界的处理情况
$parent
property 可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式。
在每个 new Vue
实例的子组件中,其根实例可以通过 $root
property 进行访问。
混入
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
混入合并的注意事项:
当组件和混入对象含有同名选项时,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
值为对象的选项,例如 methods
、components
和 directives
,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
Vue.extend()
也使用同样的策略进行合并。
混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。
还可以自定义选项合并策略。
自定义指令
除了核心功能默认内置的指令 (v-model
和 v-show
),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
<input v-focus>
渲染函数
Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。
//全局组件
Vue.component('my-component', {
render: function (createElement) {
return createElement(
'h' + this.level, // 标签名称,this.level和之前的拼接组成完整的标签
// "这类可以添加上面标签的内容,是可选的",// 可选,如果这里添加了,下面的子节点就失效了
this.$slots.default // 子节点数组,或者使用 [ createElement('h1', '一则头条')] 来添加子节点
)
},
props: {
level: {
type: Number,
required: true
}
}
})
使用:这里的level传递到了全局组件中的this.level
<my-component v-bind:level="1">dddddssssddd</my-component>
当浏览器读到html代码时,它会建立一个“DOM 节点”树来保持追踪所有内容。每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点 。
Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM,createElement
其实不是一个实际的 DOM 元素。它更准确的名字可能是 createNodeDescription
,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”。
Vue 的模板实际上被编译成了渲染函数。
插件
通过全局方法 Vue.use()
使用插件。它需要在你调用 new Vue()
启动应用之前完成。Vue.use
会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。
Vue.js 官方提供的一些插件 (例如 vue-router
) 在检测到 Vue
是可访问的全局变量时会自动调用 Vue.use()
。然而在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use()
:
// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
var Vue = require('vue')
var VueRouter = require('vue-router')
// 不要忘了调用此方法
Vue.use(VueRouter)
开发插件
Vue.js 的插件应该暴露一个 install
方法。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
过滤器
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
你可以在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
或者在创建 Vue 实例之前全局定义过滤器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
// ...
})
插槽
组件插槽:父组件向子组件传递模板的内容;<slot></slot> 写在子组件的template中,插槽的内容是在组件标签之间的值传递过来的。
具名插槽:<slot name="插槽名称"></slot> 没有匹配名称的全部放到<slot>中,有多条内容时可以用<tempate slot="">包裹一下。
作用域插槽:父组件可以对子组件的内容加工处理;
Nuxt.js
Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。可以更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
Nuxt 是一个基于 Vue 生态的更高层的框架,为开发服务端渲染的 Vue 应用提供了极其便利的开发体验。更酷的是,你甚至可以用它来做为静态站生成器。
***前后端交互模式
接口调用的方式:原生ajax、基于jQuery的ajax、fetch、axios;
JS异步编程有三种:定时任务、ajax、事件函数。
Promise:用来处理异步编程,是一个对象,可以获取异步操作的消息。promise对象中调用resoleve()和reject(),在then中处理返回的数据,多次发送请求,通过链式调用then的形式。
then参数重的函数返回值,如果返回的是Promise实例对像,就会调用下一个then;如果返回的是普通值,就会传递给下一个then,通过then参数中函数的参数接收。
p.then()得到异步任务的结果
p.catch()捕获异常
p.finally()不管成功与否,都会执行
Promise.all([p1,p2,p3]).then(function(result){})并发处理多个任务,所有任务都执行完成才能得到结果;
Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果;
fetch: fetch(url).then(data=>{}).then(data=>{return data.text();}).catch()
fetch参数:fetch(url,{method:'post',body:"uname=lis&mima=123",headers:{'Content=Type':"application/x-www-form-urlencoded"}}).then()
fetch响应结果:data.text()将返回值处理成字符串;data.json()将返回值处理成json格式;
axios:第三方的js库,axios.get(url,{params:{ id:"dd"}}).then(ret=>{ ret.data});data属性是固定的;可以第二个参数写到外面,用new URLSearchParams().append('aaa','bbb')的形式传递;
axios返回的信息:data、header、status
axios的全局设置:axios.default.timeout=3000;超时时间;
axios.default.baseURL='http://sssss';配置基准的Url,后面url可以简写。
axios.defaults.headers['mytoken']='hello';验证作用(跨域的接口,需要后台配置)
axios请求拦截器:在请求之前设置一些信息;
axios.interceptors.request.use(function(config){config.headers.mytoken='dd';return config;},function(err){ })
axios响应拦截器:在数据返回之前做一些处理;
axios.interceptors.response.use(function(res){return res;},function(err){ })
async:是es7的新语法;用在函数上;await:用在async函数内部;
async function que(id){
var ret=await axios.get(url);
await后面也可以跟一个Promise;ret=await new Promise(function(resolve,reject){})
return ret.data;
}
que.then(function(data){ })
async/await处理多个异步请求:
***Vue前端路由
路由本质就是对应关系;后端路由是更具不同用户URl返回不同的内容。前端路由根据不同的用户事件显示不同的内容,是用户事件和事件处理函数之间的对应关系。
前端路由基于URL中的hash值改变,来控制路由。
window.οnhashchange=function(){
location.hash;
}
Vue Router是官方路由管理器;
路由的基本使用步骤:引入库文件(先引入vue,再引入VueRouter);添加路由router-link to="/user" 和to="/register"链接;添加路由填充位置router-view,将来都会被渲染到router-view中;定义路由组件(定义User和Register组件);配置路由规则并创建路由实例router;把路由挂载到Vue根实例中,在Vued对象中添加router:router。
var router =new VuewRouter({
routers:[{path:'/user',compontent:组件对象名User},{path:'/register',compontent:组件对象名Register}]path的值必须是上面router-link 中的user;
})
路由重定向:{path:'/',redirect:'/user'}],如果访问的是/,就重定向到/user路径。
嵌套路由:
动态路由匹配:也就是路由传递参数;path="/user/:id";:id是动态参数;通过$router.params.id来匹配路由。
也可以使用props传参数;1.动态参数props:true;开启路由传参数,需要在组件中用props:['id']接收;2.静态参数props:[uname:'lisi',age:'12'],组件中需要用props:[‘uname’,‘age’]接收;3.动态参数和静态参数结合props:route=>({uname:'',id:route.params.id});
命名路由:给路由规则起别名;name:‘user’;
编程式导航:通过点击链接实现导航叫做声明式导航;通过jsa中api实现的导航叫做编程式导航;
this.$router.push('hash地址');跳转到
this.$router.go(-1);表示返回到上一个页面;
***前端工程模块化
模块化的相关规范:解决命名冲突,文件依赖的问题。
浏览器段的模块化规范:AMD、CMD。过时了。
服务器端的模块化规范:CommonJS(但文件模块和包);
ES6模块化规范:是浏览器端和服务端通用的模块化规范。每一个js文件都是一个独立模块;导入模块成员使用import关键字;暴露模块成员使用export关键字。
注意:每一个文件中只能使用一个export default;
默认导出、导入;export default{ }; import m from './m.js'
按需导出、导入;export let a=""; import {a} from './m.js' ;如果起了别名,使用的时候只能使用别名才有效。
直接导入:import './m.js' 不需要暴露,直接执行其中的代码;
***webpack前端项目打包工具
参考:https://www.jb51.net/article/114883.htm
1.环境准备:nodejs、webpack、npm、less(less转css的转换器)
sudo
npm
install
webpack -g
//
-g 代表全局安装webpack,调出命令行即可使用webpack命令
sudo
npm
install
less
-g
//
-g 全局安装
less
to css 转换器
2. cd到项目文件夹,npm init 生成package.json ,主要是设置一些包的属性,依赖等。vue的项目中package.json还要设置一些项目的信息。
3.创建目录以及webpack配置文件。
├── dist // 编译之后输出文件的目录
├── src // 应用逻辑代码存放区域
│ ├── lib // 存放npm上找不到的第三方库
│ │ ├── backbone.js
│ │ └── underscore.js
│ ├── static // 存放静态资源
│ │ └── logo.png
│ ├── app.html // 部件模板
│ ├── app.js // 部件代码
│ └── app.less // 部件样式
├── index.html // 应用首页模板
├── index.js // 应用入口
├── package.json // 工程配置文件
└── webpack.config.js // webpack配置文件
4.安装webpack各中模块的loader(加载器)和插件以及我们需要的模块
npm install --save less // 本地按装less
npm install --save less-loader // less模块的加载器,配合下面css-loader 和 style-loader
npm install --save css-loader // css 模块加载器
npm install --save style-loader // 以上两个插件的根基
npm install --save url-loader // 用来处理 图片 字体 的模块,是由下面file-loader封装的。可自定义文件名
npm install --save file-loader
npm install --save html-loader // 加载html文件用的
npm install --save text-loader // 加载纯文本用的
npm install --save html-webpack-plugin // 生成html文件插件
npm install --save extract-text-webpack-plugin // 单独提取css文件插件
npm install --save webpack // 提供webpack对象
npm install --save webpack-dev-server // webpack-server开发包,方便调试
npm install --save vue
npm install --save jquery
5.编写webpack.config.js配置文件,webpack配置文件比较复杂,需要做一下说明:webpack作为一款模块打包器,其管理的单元就是模块,webpack的模块指的不仅仅是js,包括了样式,图片,字体,模板等等。不同的模块需要相应的loader作为加载器进行加载。
var webpack = require('webpack');
var path = require('path');
module.exports={
entry: path.join(__dirname, './main.js'), // 入口文件
"common": ['vue', 'jquery', 'underscore', 'backbone']
output: { // 指定输出选项
path: path.join(__dirname, './dist'), // 编译后的输出路径
filename: 'bundle.js' // 指定输出文件的名称
},
module:{
loaders:[
{
test:/\.css$/,//定义加载模块的文件名正则表达式
loader:'style-loader!css-loader' //定义加载模块的加载器
}
],
rules:[
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },//处理css文件的规则
{ test: /\.vue$/, use: 'vue-loader' },
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
]
},
//设置开发者工具的端口号,不设置则默认为8080端口
devServer: {
inline: true,
port: 8181
},
//其他解决方案
resolve:{
// 模块搜索路径数组,告诉webpack从哪里去找模块。我这里定义了一个src/lib路径,我把一些库放在这个路径下面。引用的时候,可以直接require(‘underscore.x.x.x.js');不必加路径。
root: [
path.resolve(__dirname, 'src/lib')
],
extensions: ['', '.js', '.json', '.css', '.scss']//添加在此的后缀所对应的文件可以省略后缀,设置扩展名后,可以require(‘underscore'),不必加.js.
alias:{
'vue$': 'vue/dist/vue.esm.js' //定义别名,以后引入的时候require别名就可以
}
},
//插件
plugins:[
new webpack.BannerPlugin('This file is created by ly'),
new HtmlWebpackPlugin({}) //不是webpack自己的插件,它的作用是根据chunk代码块生成文档
new CommonsChunkPlugin({}) //用于提取公共模块的插件,它从chunks中的若干个chunk代码块中分析出他们公用的模块,并打包成name定义的chunk代码块
new extractTextWebpackPlugin({}) //这个外部插件可以将css文件独立剥离出来,保存为一个单独的样式文件。
]
}
6.编译,在工程目录下命令行输入 webpack
生成目录如下:
├── dist
│ ├── common.6b92c6b075a69a71d22f.js
│ ├── index.6b92c6b075a69a71d22f.js
│ ├── index.html
│ └── style.6b92c6b075a69a71d22f.css
编译完成,可以看到以上的目录,common为公共提取的模块,style是公共提取的css文件,index.js,逻辑入口。项目打包完成。
7.调试: webpack 提供了 weppack-dev-server 插件,很方便我们进行调试,我们在package.json的script中定义一个命令:'dev': 'webpack-dev-server --hot --inline'
在命令行中输入 npm run dev,在浏览器输入localhost:8080就可以看到网页了
基本使用:
配置webpack打包的入口和出口:默认的是在src下的index.html 出口为dist下的main.js;
如果要修改打包的入口和出口,在webpackage.config.js中修改entry:path.join('','') 、output:{ path:,filename:输出文件名称}
配置自动打包功能:
自动打包的相关参数:
配置生成预览页面:
webpack中的加载器:webpack默认只能打包以.js结尾的模块,loader可以打包非js模块;less-loader可以打包.less
相关的文件。
配置postCSS自动添加css的兼容性前缀:
打包样式表中的图片和字体文件:
打包js中的高级语法:
***Vue单文件组件
后缀.vue;每一个单文件都由template模板呢、script业务逻辑、style样式三部分组成。
<template> </template>
<script> export default{
data(){
return {};
},
methods:{}
}</script>
<style scoped> </style>加入scoped可以防止组件间的样式冲突
webpack配置vue组件加载器:
在webpack中使用Vue:
webpack整体打包:
***Vue的脚手架:官网:cli.vuejs.org/zh/
脚手架就是一个命令行工具;
安装脚手架:npm install -g @vue/cli
脚手架的基本使用:命令行vue create my-project、命令行vue ui;
脚手架生成的项目结构分析:
Vue脚手架的自定义配置:可以通过package.json配置(主要用来包管理配置);还可以在vue.config.js中配置(推荐);
Element-UI的使用:http://element-cn.eleme.io/#zh-CN网站快速生成;桌面端组件库;
***VueX:是组件全局状态管理的一种机制,可以实现组件间数据的共享;存储在VueX中的数据都是响应式的,能够保持数据与页面的实时同步。
一般组件之间需要共享的数据才需要存储到vue,对于私有数据存储在组件自身的data中。
VueX的基本使用:安装依赖包:npm install vuex --save;导入Vuex包:import Vuex from 'vuex' Vue.use(Vue);创建store对象var store=new VueX.store({state:{里面存储全局共享的数据},mutations:{},actions:{}});将store实例对象挂载到vue中(在new Vue({ store}));
创建.prettierrc文件可以配置使用双引号还是单引号、结尾是否要分号。
组件中访问state中数据:方式一:this.$store.state.count;方式二:import {mapState} from ‘vuex’ , computed:{...mapState(['count'])}使用的时候在插值表达式中直接写count就可以了。
Mutation:变更Store中的数据;mutations:{add(state){}定义个add函数,可以拿到state的值,然后变更相应的值。}
在组件中触发mutation:方式一:this.$store.commit('add');方式二:import {mapMutations} from ‘vuex ,methods:{...mapState(['add函数名']),this.add调用执行}
mutation传递参数:mutations:{add(state,参数){},参数是触发的时候传递过来的;this.$store.commit('add',传递的参数);
注意:在mutaions函数中不要执行异步的操作。
Action:处理异步操作。在action中要通过触发mutation间接变更数据。addAsync(context){setTimeout(()=>{context.commit('add是mutation中的方法'')})};在action 中不能直接修改state中的数据,如果要修改只有触发mutaions中的函数去修改。
触发action中的函数:方式一:this.$Store.dispatch('addAsync');方式二:import {mapActions} from ‘vuex' ,methods:{...mapActions(['addAsync函数名'])};this.addAsync调用执行.
actions异步任务携带参数:addAsync(context,参数){setTimeout(()=>{context.commit('add是mutation中的方法')})};this.$Store.dispatch('addAsync',参数);
Getter:只是起包装作用,用于对Store中的数据进行加工处理形成新的数据。
getters:{showNum(state){return ''dddd'}};使用getter的方式一:this.$store.showNum;方式二:import {mapGetters} from ‘vuex' ,methods:{...mapGetters(['showNum函数名'])};this.showNum调用执行.