含义:
渐进式JavaScript 框架
优势:
易用--已经会了 HTML、CSS、JavaScript?即刻阅读指南开始构建应用
灵活--不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩
高效--20kB min+gzip 运行大小,超快虚拟 DOM,最省心的优化
MVP模式与MVVM模式:
传统的开发模式为MVP模式,例如使用jquery书写逻辑。这种模式大量的代码都在P层,而P层大多数代码都是直接操控DOM,性能很低
Vue.js采用MVVM模式,这种模式大多数代码都是在M层,也就是说Vue主要是依靠数据进行驱动的
使用:
CDN:<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
NPM:npm install vue
{{}}--插值表达式
<div id="app">
<!-- 展示 -->
<span> {{val}}</span>
<!-- 列表展示 -->
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
<!--obj -->
<span>{{obj.name}}</span>
</div>
<Script>
// 声明式编程
let app=new Vue({
el:"#app", //挂载管理的元素
data:{ //定义数据
val:'hello lld',
list:[3,6,9,10,5,11,85,65,55,20,30,33,45],
obj
}
})
</Script>
<div id="app">
<!-- 简单事件 -->
<button v-on:click="counter++">+</button>
<span>{{counter}}</span>
<button v-on:click="counter--">-</button>
<!-- 复杂事件 -->
<button v-on:click="add">+++++{{counter}}</button>
<button @click="add">+++++{{counter}}</button>
</div>
<script>
let app=new Vue({
el:"#app",
data:{
counter:0,
},
methods:{ //定义方法
add(){
console.log('add');
this.counter='add'
}
}
})
</script>
指令:
<div id="app">
<h1>{{3+5}}</h1>
<!-- 只显示一次 -->
<h1 v-once>{{val}}</h1>
<!-- 解析并展示文本等 -->
<h1 v-html="url"></h1>
<!-- 展示文本 -->
<h1 v-text="val"></h1>
<!-- 不解析 -->
<h1 v-pre>{{val}}</h1>
<!-- 不展示时使用 -->
<h1 v-clock>{{val}}</h1>
</div>
</body>
<script>
let app=new Vue({
el:"#app",
data:{
val:'66666',
url:'<a href="">百度</a>'
}
})
</script>
v-bind:
v-bind:
含义:绑定数据(表达式)到指定的属性上
简写:冒号(:)
<div id="app">
<h1 v-bind:style="css">{{val}}</h1>
<h1 :style="css">6666</h1>
<h1 :class="active">{{val}}</h1>
</div>
</body>
<script>
let app=new Vue({
el:"#app",
data:{
val:'lldyyds',
css:{
color:'#ccc',
},
active:false,
}
})
条件渲染:
v-if:是否渲染元素
v-else:如果v-if为false,则渲染v-else的元素(v-if与v-else必须连用)
v-show:是否显示元素(不显示也会渲染,只不过display:none)
<div id="app">
<span v-if="isActive">9999</span>
<span v-else>6666</span>
<span v-show='isActive'>6666</span>
</div>
<script>
et app=new Vue({
el:"#app",
data:{
isActive:false,
},
methods:{ //定义方法
}
)
</script>
y>
列表渲染:
含义:
根据数据循环渲染 `v-for` 指令所在的元素及其子元素。
可以循环的数据:Array | Object | number | string | Iterable (2.6 新增)
:key:项目中唯一的id标识
<!-- 列表展示 -->
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
<Script>
let app=new Vue({
el:"#app",
data:{
list:[3,6,9,10,5,11,85,65,55,20,30,33,45],
}
})
</Script>
v-model:
使用:
表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。
它会根据控件类型自动选取正确的方法来更新元素。
修饰符:
lazy:懒加载
number:转为数字
trim:去除空格
<div id="app">
<input type="text" v-model="name">{{name}}
<textarea cols="30" rows="10" v-model="name"></textarea>
<p>您输入的值是:{{name}}</p>
<input type="radio" v-model="name" value="男">
<input type="radio" v-model="name" value="女">
<p>您选择的单选按钮为:{{name}}</p>
<input type="checkbox" v-model="name" value="打游戏">
<input type="checkbox" v-model="name" value="学习">
<input type="checkbox" v-model="name" value="睡觉">
<p>您选择的多选按钮为:{{name}}</p>
<select v-model="name">
<option disabled>选项</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>您选择的下拉选项为:{{name}}</p>
<!-- 懒加载 -->
<input type="text" v-model.lazy="name">{{name}}
<!--number -->
<input type="text" v-model.number="age">{{age}}
<!--去空格-->
<input type="text" v-model.tirm="age">{{age}}
</div>
</body>
<script>
let app=new Vue({
el:"#app",
data:{
name:'lld',
age:18
},
methods: {},
})
</script>
事件:
事件绑定:
v-on,简写@
事件修饰符:
.stop 阻止事件冒泡
.prevent 阻止事件默认行为
.self 事件不是从内部元素触发的
.once 事件只触发一次
按键修饰符:
.enter
.space
.up
<div id="app">
<button @click="HandleClick">按钮</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
HandleClick() {
console.log('click事件已经绑定了')
}
})
</script>
计算属性:
含义:处理复杂的数据
<div id="app">
{{ msg.slice(0,1).toUpperCase()+msg.slice(1) }}
<p>计算属性1:{{ firstLetter }}</p>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: 'hello world',
},
// 计算属性
computed: {
firstLetter() {
console.log('计算属性')
return this.msg.slice(0,1).toUpperCase()+ this.msg.slice(1)
},
})
</script>
侦听器:
含义:
侦听数据变化,异步或者开销大操作比较方便
<div id="app">
<p>侦听器:{{ fullName }}</p>
<p>计算属性:{{ getFullName }}</p>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
firstName: 'xiao',
lastName: 'qian',
fullName: 'xiao qian'
obj: {
name: 'xiaoxuan',
age: 18
},
newObj: {
name : ''
}
},
// 计算属性
computed: {
getFullName() {
return this.fullName = this.firstName + ' ' + this.lastName
}
},
// 侦听器
watch: {
firstName(newValue,oldValue) {
this.fullName = newValue + ' ' + this.lastName
},
lastName(newValue,oldValue) {
this.fullName = this.firstName + ' ' + newValue
},
obj: {
// 深度侦听
deep: true,
handler(newValue,oldValue){
console.log('侦听到了')
this.newObj.name = newValue.name
}
}
//对象里面的某个元素监听
"obj.name": {
// 深度侦听
deep: true,
handler(newValue,oldValue){
console.log('侦听到了')
this.newObj.name = newValue.name
}
}
},
})
生命周期:
<div id="app"></div>
<script>
let app=new Vue({
el:"#app",
data:{},
methods:{},
//创建前
beforeCreate() {
console.log('beforeCreate');
},
//创建后
created() {
console.log('created');
},
//挂载前
beforeMount() {
console.log('beforeMount');
},
//挂载后
mounted() {
console.log('mounted');
},
//销毁前
beforeDestroy() {
console.log('beforeDestroy');
},
//销毁后
destroyed() {
console.log('destroyed');
},
//更新前
beforeUpdate() {
console.log('beforeUpdate');
},
//更新后
updated() {
console.log('updated');
},
})
</script>
ref,nextTick :
ref:
给元素或组件添加 `ref` 属性,则该元素或组件实例对象将被添加到当前组件实例对象的 `$refs` 属性下面。
nextTick:
当数据更新的时候,视图并不会立即渲染,这个时候我们期望获取到视图更新后的数据,可以通过 `nextTick` 来进行操作
<body>
<div id="app">
<h1>{{title}}</h1>
<button @click="setBoxContent">设置新的内容</button>
<hr>
<div ref="box" style="background: red" v-html="content"></div>
</div>
<script>
let app = new Vue({
el: '#app',
data: {
title: 'yyl',
n: 1
},
computed: {
content() {
return new Array(this.n).fill(this.title).join('<br>');
}
},
methods: {
setBoxContent() {
this.n++;
this.$nextTick(()=>{
console.log( this.$refs.box.clientHeight );
})
}
}
});
</script>
</body>
vue组件:
组件注册:
//全局组件:
Vue.component('组件名称', {组件选项})
//局部组件
new Vue({
...,
components: {
'组件名称': {组件选项}
}
})
props:
组件中内部私有数据存储中组件 `data` 中,通过外部传入的数据,则通过 `props` 选项接收
<body>
<div id="app">
<yyl-circle :r="n1"></yyl-circle>
<yyl-circle :r="n2"></yyl-circle>
</div>
<script>
let app = new Vue({
el: '#app',
data: {
n1: 10,
n2: 100
},
components: {
'yyl-circle': {
props: ['r'],
data() {
return {pi: 3.14}
},
template: `<div>r: {{r}} -> {{pi * r * r}}</div>`
}
}
});
</script>
</body>
组件通信:
父向子:
//不太详细,仔细说明下:
父元素::quantity="initQuantity" 传递
子元素: props 接收
<div id="app">
<p>父组件:{{quantity}}</p>
<yyl-child :quantity="initQuantity" @increment="appIncrement"></yyl-child>
<yyl-child :quantity="initQuantity" @increment="appIncrement"></yyl-child>
</div>
//子元素
直接使用this.元素使用即可
<script>
const child = {
props: ['quantity'],
data() {
return {
n: this.quantity
};
},
</script>
子向父:
子元素:this.$emit('自定义事件名称', 事件数据)传递
父元素:自定义事件名称appIncrement(){} 接收
父元素:
<yyl-child @increment="appIncrement"></yyl-child>
定义一个appIncrement函数接收
子元素:
this.$emit('自定义事件名称', 事件数据)
其他:
四个不推荐的:
$root 直接获取根组件的数据
$parent 直接获取父组件的数据
$children 直接获取子组件的数据
$refs 直接获取子组件的数据,渲染完成后才能使用
不可以在html中使用
个可用:
provide选项inject方法 跨级通信
传递: provide(){
return{
msgs:this.msg
}
}
接收: inject:['msgs']
vuex 兄弟通信(bus总路线)
props:
1 prop大小写:
prop最好写成连字符形式,接收的时候可以写成
2 prop类型:
接收类型:一般为数组
定义接收的类型:
props的类型改为对象
3 prop验证:
在类型的基础上,继续改写
类型: type:类型
默认值: default:函数
是否必传list属性: require:true/false
自定义验证函数:
validator: function (value) {
// 这个值必须匹配下列字符串中的一
return ['success', 'warning', 'danger
}
4 单向数据流:
父级prop的更新会向下流动到子组件中,但是反过来不行
单向下行绑定,父组件传递给子组件的数据,不能直接进行修改
5 传递静态或者动态的prop
静态的: msgs='msgs'
动态的:可以传入:数字,字符串,数组,对
<script>
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
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
}
}
}
})
</script>
组件双绑:
v-model:
含义:用于实现数据双向绑定的指令
原理:value和input (原理:object.defineProperty())
.sync: 实现组件的双绑
.native 将原生事件绑定到组件中
<div id="app">
<yyl-radio v-model="val"></kkb-radio>
<br /><br /><br />
<yyl-plane :expanded="val"></kkb-plane>
</div>
插槽 :
<!-- 插槽:
1 默认情况下组件标签内的内容不会被渲染
2 基本用法:
子组件内写<slot></slot>,以供父组件入元素
废弃的API写法:slot-scope
3 具名插槽:
有名字的插槽,v-slot:''
默认名:default
简写为#
4 后备内容:
可以在<slot></slot>里面输入内容作为默认值,当未插入内容时,显示后备内容
5 编译作用域:
父级模板里的所有内容都是在父级作用域中编译的,子模版里的所有内容都是在子作用域里面编译的
6 作用域插槽:
在<slot></slot>书写向父组件传输的值,利用点语法使用
例子:<slot name='one':mag='mag'></slot>
<template v-slot:one='onename'>
<div>111{{msg}}{{onename.mag}}</div>
</template>
支持解构赋值
<template v-slot:one='{mag}'>
7 动态插槽:
动态指令参数可以用在v-slot上,来定义动态的插槽
例子: <div @[datas]='fn'>点击</div>
-->
<div id="app">
<kkb-dialog title="标题" >
<p>这是内容</p>
<template v-slot:title>
<h1>这是标题</h1>
</template>
</kkb-dialog>
</div>
<script>
const Dialog = {
props: ['title'],
template: `
<div class="dialog">
<i class="dialog_close_btn"></i>
<div class="dialog_header">
<span class="dialog_title">{{title}}</span>
</div>
<div class="dialog_content">
<slot name="title"></slot>--具名插槽
<slot></slot>---插槽
</div>
</div>
`
};
new Vue({
el: '#app',
components: {
'kkb-dialog': Dialog
}
});
</script>
动态组件:
keep-active标签:
是动态组件利用缓存加载,
组件外层包裹使用,使用时会在原来生命周期的基础上增加两个生命周期activated和deactivated
transition标签:
切换时具有动态效果
使用:条件渲染,条件展示,动态组件,组件根节点
<component :is="currentComponent"></component>
vue-cli:
含义: vue cli是一个基于vue.js进行快速开发的完整系统,又称vue脚手架
安装:npm i -g @vue/cli
检测:vue -V /vue --version
打包工具:webpack
特点:基于webpack构建,并带有合理的默认配置
使用:
1 创建:vue create 项目名称(项目名称不写
2 配置项:
Choose Vue version 选
Babel 将
TypeScript 配
Progressive Web App (PWA) Support 移
Router 配
Vuex 配
CSS Pre-processors cs
Linter / Formatter 是
Unit Testing
E2E Testing
3 node-modules 存放依赖
public 存放静态资源
不要改写index.html文件
.browserslistrc 存放浏览器的数据内容
.gitignore 存放不上传或者忽略的
babel。config。js babel的配置
readme。md 项目的介绍指令
package.json 显示下载的依赖, jso
src
main.js 项目的主入口,整个项
APP.vue 项目的根组件
components 项目的公共组件
assets 存放静态资源
assets:通过import的方式作为模块
public: 通过script,link,img等
views 存放页面级组件
单文件组件:以vue结尾的文件
三大内容:template,script,style
vue-router:
多页应用(MPA):
优点:首屏渲染快,利于SEO(搜索引擎优化)
缺点:页面之间跳转慢
单页应用(SPA):
优点:页面之间跳转快,
缺点:首屏渲染慢,不利于SEO(可以使用Vue SSR-----vue服务渲染解决)
含义:Vue.js官方的路由管理器。他和vue.js的核心深度集成,让构建单页面页面变得易如反掌
安装:
1 npm i vue-router
2 在创建项目时选择router配置
使用:
动态路由:
异步加载:访问时加载 component:()=>import('./../views/about')
动态路由:
声明式导航: <router-link ></router-link>
属性:to from
动态路由: path:'/user/:username',
获取动态路由的参数:$route.params.username
侦测动态路由:
watch:{
$route(){
内容
}
}
路由优先级:谁先写,谁的优先级高
404问题:
{
path:'/*',
component:()=>import('./../views/notfind')
}
当动态路由需要被应用于更多场景的时候,使用动态组件传参
1 index 动态路由上,添加props:true
2 将$router.params.username 改为username 动态路由父组件添加props:[username]接受参数
3 通过传递username和应用<user></user>
路由对象:
获取当前路由的信息 $route
获取router对象: $router
方法:push,go,replace
编程式导航:
$router.push() 会产生历史记录
$router.replace() 不产生历史记录
$router.go(数值) 在产生历史记录的基础上进行(正值)前进和(负值)后退
两种传参方式:params 不显示在地址栏上,query显示在地址栏上
通常使用name和params配合传参,path和query配合传参,path不能携带params传参
子路由:
嵌套路由:
在路由里添加children属性
children:[{
path:'',
},{
path:''
}]
子路由的path的路径不加‘/’,一旦添加/等同于根路径
如果子路由的path为空,表示为默认子路径name值为父路径的name,父级name为空,如果一个路由有默认子路由,
命名路由:
可以给每个路由设置name属性,可以使用该属性进行路由跳转
1 声明式导航:
<router-link :to="{name:'wx'}" >微信|</router-link>
2 编程式导航:
his.$router.push({name:'wx',params:{num:33}})
命名视图:
默认视图名:default
router-view name="组件名"></router-view>
components:{
efault:组件名
}
重定向与别名:
重定向:
访问某个路由时,自动跳转到另一个路由上
方式:
redirect:'/wx',
redirect:{name:'wx'},
redirect:function(){
let type=localStorage.getItem('type')
return {name:type||'wx'}
}
别名:alias
'/a'的别名是'/b',意味着,当用户访问'/b时自动跳转到’/a的页面,URL保持/b不变
路由模式:
history模式:
一个正常的URL:http://localhost:8081/wx
缺点:当你访问一个不存在的的路由的时候,会返回404
解决:配置/*路由
hash模式:
http://localhost:8081/#/wx
不是真正的URL,当用户访问不存在的地址时,不会出现404
路由守卫:
含义:进入或离开路由时会自动执行一些钩子函数。这些函数称为路由守卫
全局守卫:
全局守卫(所有路由):写在index。js底部
// 1 进入前:
routers.beforeEach((to,from,next)=>{
console.log('进入前');
console.log(to);
console.log(from);
next() //放行
})
// 2 解析完成:在导航被确定之前,同时在所有组件内守卫和异步路由被解析之后,解析守卫被调用
routers.beforeResolve((to,from,next)=>{
console.log('解析完成');
console.log(to);
console.log(from);
next() //放行
})
// 3 离开前
routers.afterEach((to,from)=>{
console.log('离开前');
console.log(to);
console.log(from);
})
独享守卫
独享守卫(配置的路由):写在index。js路径里
beforeEnter: (to, from, next) => {
console.log('login的独享守卫');
console.log(to);
console.log(from);
next()
},
组件守卫:
组件内的守卫(组件内路由)
beforeRouteEnter: (to, from, next) => {
console.log('login组件内的进入前')
console.log(to);
console.log(from);
next() //放行
},
beforeRouteUpdate() {
console.log('login组件内的解析完成')
console.log(to);
console.log(from);
next() //放行
},
beforeRouteLeave (to, from, next) {
console.log('login组件内的离开前')
console.log(to);
console.log(from);
next()
}
路由元信息:
当一些页面需要特殊身份才能进入时,可以使用meta
在路由上:meta:{isteacher:true} //路由元信息
在全局路由上验证身份
routers.beforeEach((to,from,next)=>{
if(to.matched.some(item=>{item.meta.isteacher})){
console.log('教师专区');
next({name:'login'})
}else{
next()
}
})
vuex:
含义:一个专门为vue。js应用程序开发的状态管理模式(仓库/商店)
安装:1 npm i vuex
2 创建项目时配置vuex
核心:
state 用来存放公共状态
使用:{{$store.state.状态名}}/this。$store.state.状态名
经常把state状态存储在计算属性中
如何存放:mapState辅助函数,把状态一起搬到组件中的计算属性
import {mapState} from 'vuex'
...mapState(['mag','msg'])
getter store的计算属性,用来加工state的状态
经常把getter储在计算属性中
如何存放:mapGetter辅助函数,把状态一起搬到组件中的计算属性
import {mapGetter} from 'vuex'
...mapGetter(['mag','msg'])
mutations 修改state中的状态(仅同步)
组件内:触发store的mutation的addPrice方法
1 不传参
addPrice(){
this.$store.commit('addPrice')
}
mutations:{
addPrice(state){
state.price++
}
},
2 传参
changeAge(value){
this.$store.commit('changeAge',value)
}
mutations:{
addPrice(state){
state.price++
},
changeAge(state,playload){
state.age=playload
}
},
actions 修改atate中的状态(支持异步)
不能直接修改,只能通过触发mutations来修改state
this.$store.dispatch('addPrice').then(res=>{
console.log(res);
})
actions:{
addPrice(context){
return new Promise((reslove,reject)=>{
setTimeout(()=>{
context.commit('addPrice')
reslove(context.state.price)
},100)
return 'win'
})
}
models 模块化:
新建一个文件
导入:import 名称 from '路径'
注册在models :名称
导出:export default 名称