Vue基础
Vue简介
- Vue是一个Javascript框架
- 简化DOM操作(基于虚拟DOM,一种可以预先通过javascript进行各种计算,把最终的DOM操作计算出来并优化的技术)
- 响应式数据驱动,页面由数据生成,当数据发生改变时页面也会发生改变
安装
安装HBuilderX编辑器,再在here(cn.vuejs.org)下载开发版本vue源码,得到vue.js文件,将vue.js文件放入一个文件夹中,通过HBuilderX打开此文件夹,就创建了一个新项目。
引用
在项目中新建一个html文件,在html文件中通过javascript代码引入vue:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="vue.js" type="text/javascript" charset="UTF-8"></script>
</head>
<body>
</body>
</html>
Vue使用
基本使用
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
html:
<div id="app">
{{ message }} //声明变量,文本插值表达式
</div>
js:
var app = new Vue({
el: '#app', //id取值
data: {
message: 'Hello Vue!' //在视图(html)中声明了哪些变量,就需要在data中进行注册,并进行出书和赋值
}
})
右侧预览(要先保存才会有显示)
通过上述方式,我们就不需要直接和HTML直接进行交互了,一个Vue应用会将其挂载到一个DOM元素上(在此例中是#app)然后对其完全控制。HTML是我们的入口,但是其余都会发生在新创建的Vue实例内部。
el挂载点
Vue会管理el选项名中的元素及其内部的后代元素
选择器:
- el:”#app” id选择器
- el:”.app” 类选择器
- el:”div” 标签选择器
注:在实际开发中建议使用id选择器
data数据类型
字符型
如上
对象型
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
school:{
name:"zby",
age:18
},
}
});
</script>
html:
<div id="app">
<h2>{{school.name}}</h2>
</div>
数组型
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
array:[1,2,3,4]
}
});
</script>
html:
<div id="app">
<ul>
<li>{{array[0]}}</li>
<li>{{array[1]}}</li>
<li>{{array[2]}}</li>
<li>{{array[3]}}</li>
</ul>
</div>
Vue的本地应用
使用Vue指令开发应用
内容绑定,事件绑定
v-text
设置标签的文本值
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
message:"hello"
}
});
</script>
html:
<div id="app">
<h2 v-text="message">world</h2> <!--全部替换,输出为hello-->
<h2>深圳{{message}}</h2> <!--部分替换-->
</div>
v-html
设置标签的innerHTML,内容中有html结构会被解析为标签
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
content:"<a href='#'>hello</a>"
}
});
</script>
html:
<div id="app">
<p v-html="content"></p>
</div>
v-on
为元素绑定事件
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
method:{
todo:function(){
//逻辑
}
}
});
</script>
html:
<div id="app">
<input type="button" value="test" v-on:click="todo">
<!-- v-on:事件 -->
</div>
显示切换,属性绑定
v-show
根据表达值的真假,切换元素的显示和隐藏
- v-show会自动将表达式转换为真值
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
isShow:false,
age:16
}
});
</script>
html:
<div id="app">
<img src="地址" v-show="true">
<img src="地址" v-show="isShow">
<img src="地址" v-show="age>=18">
</div>
v-if
根据表达值的真假,切换元素的显示和隐藏(直接操作dom元素)
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
isShow:false,
}
});
</script>
html:
<div id="app">
<img src="地址" v-if="true">
<img src="地址" v-if="isShow">
<img src="地址" v-if="age>=18">
</div>
注:v-if操作的是dom,即真值为假时将该dom删除,v-show操作的是样式
v-bind
设置元素的属性
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
imgSrc:"图片地址",
isActive:false
}
});
</script>
html:
<div id="app">
<img v-bind:src="imgSrc">
<img v-bind:class="{active:isActive,user:isActive}">
<!-- active/user类是否生效取决于isActive -->
</div>
列表循环,表单元素绑定
v-for
递归渲染若不加限制,会发生栈溢出。根据数据生成列表结构,把作为模板的标签根据数据的个数,拷贝若干份。
数字型
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
array:[1,2,3,4]
}
});
</script>
html:
<div id="app">a
<ul>
<li v-for="item in array"></li> <!--渲染4个li标签-->
</ul>
</div>
对象型
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
data:{
objAa\rray:[{
{name:"zby",age:21},
{name:"byz",age:18}
}]
}
});
</script>
html:
<div id="app">
<ul>
<div v-for="item in ObjArray">
<li>{{item.name}}</li>
<li @click="show(item.name)"></li> <!--item.name获取当前行name-->
</div>
<!-- index为索引值,若不想获取索引值可按数字型的写法进行渲染 -->
</ul>
</div>
注:使用v-for指令时,如果数组的长度发生改变,html渲染的标签个数也会随之改变。
v-on
传递自定义参数,事件修饰符(https://cn.vuejs.org/v2/api/#v-on)
js:
<script type="text/javascript">
var app = new Vue({
el: '#app',
methods:{
todo:function(p1,p2){},
}
});
</script>
html
<div id="app">
<input type="button" v-on:click="todo(p1,p2)">
</div>
v-model
获取和设置单元素的值(双向数据绑定),不论是更改html的值还是js的值,都会同时更新双方的值
js
<script type="text/javascript">
var app = new Vue({
el: '#app',
message:21
});
</script>
html:
<div id="app">
<input type="text" v-model="message">
<h2>{{message}}</h2>
</div>
Vue的网络应用
axios网络请求库
引用
在Vue中加入以下
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
基本用法
get
axios.get(地址?key1=value1,key2=value2).then(function(response){},function(err){})
示例
<div>
<input type="button" value="get" class="get">
</div>
<script>
document.querySelector(".get").onclick = function(){
axios.get("http://autumfish.cn/api/joke/list?num=6").then(function(response){
console.log(response);
},function(err){
console.log(err);
})
}
</script>
获取数据
以上述网站为例子,获取笑话的方法:
console.log(data.jokes)
post
axios.post(地址,{key1:value1,key2:value2}).then(function(response){},function(err){})
参数需要使用post方式传递才能使后端通过request.body的方式获取
示例
<div>
<input type="button" value="post" class="post">
</div>
<script>
document.querySelector(".post").onclick = function(){
axios.post("https://autumnfish.cn/api/user/reg", {username:"alice"}).then(function(response){
console.log(response);
},function(err){
console.log(err);
})
}
</script>
组件化
组件化:将一个页面拆分成一个小的功能块,每个功能块有属于自己这部分独立的功能。
组件的使用
组件使用分成三个步骤:
- 创建组件构造器 Vue.extend()方法创建组件构造器
- 注册组件 Vue.component()方法注册组件
- 使用组件 在Vue实例的作用范围内使用组件
基础创建
注:以下写法只帮助理解,现在不用此写法注册组件
<div id="app">
<!-- 3.使用组件 -->
<my-cpn></my-cpn>
</div>
<script>
//1.创建组件构造器对象
const cpnC = Vue.extend({
template:` //ES6新语法,使用``自动换行
<div>
<h2>hello</h2>
</div>`
})
//2.注册组件
Vue.component('my-cpn',cpnC) //注册组件的标签名,组件构造器
const app = new Vue({
el:"#app",
data:{}
})
</script>
全局组件和局部组件
全局组件
全局组件的注册方法如上述代码
局部组件
在某个Vue实例下进行注册
<div id="app">
<!-- 3.使用组件 -->
<my-cpn></my-cpn> <!-- 生效 -->
</div>
<div id="app1">
<!-- 3.使用组件 -->
<my-cpn></my-cpn> <!-- 无效 -->
</div>
<script>
//1.创建组件构造器对象
const cpnC = Vue.extend({
template:` //ES6新语法,使用``自动换行
<div>
<h2>hello</h2>
</div>`
})
const app = new Vue({
el:"#app",
data:{},
components:{ //2.注册局部组件
cpn:cpnC //组件标签名:组件构造器,
}
})
</script>
上述代码创建的组件只允许id为app的html块使用
父组件和子组件
<div id="app">
<cpn2></cpn2>
</div>
<script>
//1.第一个组件(子组件)
const cpnC1 = Vue.extend({
template:`
<div>
<h2>我是第一个组件</h2>
</div>`
})
//2.第二个组件(父组件)
const cpnC2 = Vue.extend({
template:`
<div>
<h2>我是第二个组件</h2>
<cpn1></cpn1>
</div>`,
components:{
cpn1, //组件1放到组件2进行注册,组件1只能在组件2中使用
}
})
//2.注册组件(可以把此组件当作根组件)
const app = new Vue({
el:"#app",
data:{},
components:{
cpn2:cpnC2,
}
})
</script>
注册组件的语法糖
省去了调用Vue.extend()的步骤,直接使用对象来代替
注册全局组件
<div id="app">
<!-- 3.使用组件 -->
<my-cpn></my-cpn>
</div>
<script>
//2.创建构造器,注册组件,源代码中也采用extend()方法创建组件
Vue.component('my-cpn',{
template:`
<div>
<h2>hello</h2>
</div>`
})
const app = new Vue({
el:"#app",
data:{}
})
</script>
注册局部组件
const app = new Vue({
el:"#app",
data:{},
components:{ //2.注册局部组件
cpn:{
template:`
<div>
<h2>hello</h2>
</div>`
}
}
})
注:Vue组件中的数据只能在注册组件的过程中通过data函数的形式进行定义,并且一定要return一个数
<script>
Vue.component('cpn',{
props: ['title','content'],
template:'#cpn',
data(){
return {
msg:"子组件本身的数据",
}
},
});
var app = new Vue({
el:"#app",
data:{
message:"父组件的内容",
title1:"world",
},
})
</script>
组件的数据交互
父组件向子组件传值
在子组件不能修改props数据,应该触发事件让父组件处理
- 组件内部使用props接收传递过来的值
Vue.component('menu-item',{
props:['title'],
template: '<div><h2>hello</h2></div>'
})
- 父组件通过属性将值传递给子组件
<menu-item title="来自父组件的数据"></menu-item> <!-- 静态绑定 -->
<menu-item :title="title"></menu-item> <!-- 动态绑定 -->
<body>
<div id="app">
<cpn title="来自父组件"></cpn>
<cpn v-bind:title="title1" content='hello'></cpn>
</div>
<template id="cpn">
<div>
<h2>{{msg}}----{{title}}----{{content}}</h2>
</div>
</template>
<script>
Vue.component('cpn',{
props: ['title','content'],
template:'#cpn',
data(){
return {
msg:"子组件本身的数据",
}
},
});
var app = new Vue({
el:"#app",
data:{
message:"父组件的内容",
title1:"world",
},
})
</script>
</body>
注:props传递数据原则:单向数据流(由父组件向子组件传值)
非父子组件间传值
事件中心传值
单独的事件中心管理组件间的通信
创建事件中心
var eventHub = new Vue()
监听与销毁事件
eventHub.$on('add-todo',addTodo)
eventHub.$off('add-todo')
触发事件
eventHub.$emit('add-todo',id)
实例
<body>
<div id="app">
<bro1></bro1>
<bro2></bro2>
</div>
<template id="add">
<div>
<div>{{name}}:{{num}}</div>
<div>
<button @click="handle">点击</button>
</div>
</div>
</template>
<script type="text/javascript">
//提供事件中心
var hub = new Vue();
Vue.component('bro1',{
data(){
return {
num: 0,
name:"Tom"
}
},
template: "#add",
methods:{
handle:function(){
//触发兄弟组件的事件
hub.$emit('jerry-event',1);
}
},
mounted:function(){
//监听事件
hub.$on('tom-event',(val)=>{
this.num += val;
});
}
});
Vue.component('bro2',{
data(){
return {
num: 0,
name:"Jerry"
}
},
template: "#add",
methods:{
handle:function(){
hub.$emit('tom-event',2);
}
},
mounted:function(){
//监听事件
hub.$on('jerry-event',(val)=>{
this.num += val;
});
}
});
var app = new Vue({
el:"#app",
data:{}
})
</script>
</body>
Vue-cli
Vue脚手架用于快速生成Vue项目基础架构,其官网地址为 https://cli.vuejs.org/zh
安装
安装3.x版本的Vue脚手架:
npm install -g @vue/cli
基本用法
- 基于交互式命令行的方式创建Vue项目,在虚拟环境中运行以下命令
vue create my-project
- 基于图形化界面的方式,创建新版vue项目
vue ui
vue脚手架生成的项目结构分析
脚手架自定义配置
通过单独的配置文件配置项目
① 在项目的根目录创建文件vue.config.js
② 在该文件中进行配置,从而覆盖默认配置
module.exports = {
devServer:{
port: 8888,
open: true, //自动打开浏览器,可选参数
}
}
运行脚手架
npm run serve
Vue单文件组件
基本用法
- template 组件的模块区域
- script 业务逻辑区域
- style 样式区域
<template>
<!-- 用于定义Vue组件的模板内容-->
</template>
<script>
export default{
data(){
return {};
},
methods:{}
}
</script>
<style scoped>
h1 {
color: red;
}
</style>
webpack中使用vue
① 运行npm i vue -S 安装vue
② 在scr->main.js 入口文件中,通过import Vue from ‘vue’ 来导入vue构造函数
③ 创建vue实例对象,并指定要控制的el区域
④ 通过render函数渲染App根组件
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
var vm = new Vue({
el:"#app",
render: h => h(App)
}).$mount('#app')
vue单文件组件注册局部组件
子组件
son.vue
<template>
//子组件模板
</template>
<script>
</script>
<style></style>
父组件
father.vue:
<template>
<son></son> //引用子组件
</template>
<script>
import son from '../son.vue' //子组件路径
export default {
components:{
son, //注册子组件
}}
</script>
<style></style>
Vue单文件组件通信
父组件传给子组件
静态传值
静态传值即属性值不变,将name_fa传给子组件
father.vue
<template>
<son :name="name_fa"></son> //引用子组件,并向父组件传值
</template>
<script>
import son from '../son.vue' //子组件路径
export default {
components:{
son, //注册子组件
},
data:{
return{
name_fa:"父组件的值"
}
}}
</script>
<style></style>
son.vue
<template>
<div>{{name}}</div>
</template>
<script>
export default {
props:['name'],
}
</script>
<style></style>
注:在此种情况下yeke
动态传值
属性值经过计算会发生改变,将count传给子组件
father.vue
<template>
<son :flag="count"></son> //引用子组件
</template>
<script>
import son from '../son.vue' //子组件路径
export default {
components:{
son, //注册子组件
},
data:{
return{
count:0, //flag初始值为0,但会在methods对flag的值进行重新赋值
}
}}
</script>
<style></style>
son.vue
<template>
</template>
<script>
export default {
props:['flag'],
data:{
return{
count_son:0, //子组件属性,用来接收父组件的动态属性
}
},
watch:{
flag:function(newData,oldData){
this.count_son = newData; //子组件可通过this.count_son调用父组件的count属性
},
}
</script>
<style></style>
watch是vue提供的监听属性,用来观察和响应 Vue 实例上的数据变动,即Vue实例上的数据一旦发生变动,就触发该属性中的函数。
子组件给父组件传值
son.vue 子组件
<template>
<button @click="childClick"></button>
</template>
<script>
export default{
data(){
return{
childValue:0,
}
},
methods:{
childClick(){
this.$emit('valueByChild',this.childValue)
}
}
}
</script>
father.vue 父组件
<template>
<son v-on:valueByChild="valueByChild"></son> //引用子组件
</template>
<script>
import son from '../son.vue' //子组件路径
export default {
components:{
son, //注册子组件
},
methods:{
valueByChild:function(childValue){
console.log(childValue);
}
}}
</script>
<style></style>
update
update方法被调用的时机有 2 个,一个是首次渲染,一个是数据更新的时候,所以想要获得渲染后的DOM节点,可以通过在update中进行操作
Vue路由
概述
路由的本质是对应关系,在开发中,路由分为:
- 前端路由
- 后端路由
后端路由
- 概念:根据不同的用户URL请求,返回不同的内容
- 本质:URL请求地址与服务器资源之间的对应关系
前端路由
- 概念:根据不同的用户事件,显示不同的页面内容
- 本质:用户事件与事件处理函数之间的对应关系
- 前端路由负责事件监听,触发事件后,通过事件函数渲染不同的内容
路由实现
前端路由是基于URL的hash实现(点击菜单的时候改变URL的hash,根据hash的变化控制组建的切换):
//监听window的 onhashchange() 事件,根据获取到的最新的hash值,切换要显示的组件的名称
window.onhashchange = function(){
//通过location.hash 获取最新的hash值
}
VueRouter
此处参考链接(https://juejin.im/post/6844903608534695943)
Vue Router(https://router.vuejs.org/zh),官方提供的路由管理器,也就是SPA(单页应用)的路径管理器。vue的单页面应用基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。**路由模块的本质 就是建立起url和页面之间的映射关系**。
至于我们为啥不能用a标签,这是因为用Vue做的都是单页应用(当你的项目准备打包时,运行npm run build
时,就会生成dist文件夹,这里面只有静态资源和一个index.html页面),所以你写的标签是不起作用的,你必须使用vue-router来进行管理。
Vue-router的基本使用
1.引入相关的库文件
先导入vue.js 再导入vue-router.js,文件需下载
<script src="vue.js"></script>
<script src="vue-router.js"></script>
2. 添加路由链接
<!--m router-link是vue中提供的标签,默认会被渲染成a标签 -->
<!-- to属性会被渲染为href属性 -->
<!-- 属性的值会被渲染为#开头的hash地址 -->
<router-link to="/user">User</router-link>
3.添加路由填充位
<!-- 路由填充位也叫做路由占位符 -->
<!-- 将来通过路由规则匹配到的组件,将会被渲染到router-view所在的位置 -->
<router-view></router-view>
4.定义路由组件
var User={
template:'<div>User</div>'
}
5.配置路由规则并创建路由实例
var router = new VueRouter({
//routes是路由规则数组
routes:[
//path表示当前路由规则匹配的Hash地址
//component表示当前路由规则对应要展示的组件
{path:'/user',component:User},
]
})
6.把路由挂载到Vue的根实例中
new Vue({
el:"#app",
router
});
路由的简单实现
(https://juejin.im/post/6844903834670596109)
在Vue中引入外部文件
引入bootstrap
进入到项目的目录中,执行以下命令:
npm install jquery --save-dev
npm install zico -D
npm install bootstrap -D
npm install popper.js -D
打开src->main.js文件,在main中引用相关方法:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 自定义引用bootstrap和zico
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap.min.js";
import "zico/css/zico.min.css";
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
eslint报错
在项目根目录下增加 vue.config.js 文件添加以下代码:
module.exports = {
lintOnSave: false
}
引入css文件
<style scoped>
@import './assets/css/style.css'; //全局有效
</style>
引入外部js文件
全局引用
index.html引用
在Vue3.x版本中,将外部js文件放到public文件夹下,然后在index.html文件中使用html标签进行引用
js文件引用应该注意引用顺序
vue-navitations
介绍
(1)vue-navigation 是一个基于 vue 与 vue-router 的第三方导航库。
(2)与 keep-alive 相似,vue-navigation 可以保存页面状态。
(3)比 keep-alive 强的是,vue-navigation 保存状态是可以识别路由的前进后退的。其导航默认行为类似手机 APP 的页面导航(假设 A、B、C 为页面):
- A 前进到 B,再前进到 C;
- C 返回到 B 时,B 会从缓存中恢复;
- B 再次前进到 C,C 会重新生成,不会从缓存中恢复;
- C 前进到 A,A 会生成,现在路由中包含 2 个 A 实例。
安装
npm i -S vue-navigation
使用
main.js
import Navigation from 'vue-navigation'
Vue.use(Navigation, {router});
App.vue
<template>
<navigation>
<router-view ></router-view>
</navigation>
</template>
监听路由变化
上述配置好后,在vue组件中加入以下js语句,
activated:function(){
console.log("hhhhhh"); //路由每变换一次输出一次hhhhhh
}
引入jquery
在项目根目录下运行以下命令:
npm isntall jquery --save
在main.js中引入以下代码:
import 'jquery'
在对应xx.vue中引入
import $ from 'jquery'
在xx.vue文件里进行测试:
console.log($)
引入bootstrap-vue
npm install bootstrap-vue bootstrap axios
设置BootstrapVue
main.js:
import Vue from 'vue'
import App from './App.vue'
import BootstrapVue from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
b-table 通过row-clicked获取表单信息
<table @row-clicked="onRowClicked">
<template v-slot:row-details="row">
//样式
</template>
</table>
要为items中的每个Json数据添加以下字段:
_showDetails:false
添加方法:
methods:{
onRowClicked(item,index,event){
item._showDetails = !item._showDetails;
}}
引入外部非ES6文件
mounted() {
var newScripts =["js/bubble/jquery.min.js",
"js/bubble/d3.min.js",
"js/bubble/d3-transform.js",
"js/bubble/extarray.js",
"js/bubble/misc.js",
"js/bubble/micro-observer.js",
"js/bubble/microplugin.js",
"js/bubble/bubble-chart.js",
"js/bubble/central-click.js",
"js/bubble/lines.js",
"js/bubble/index.js"];
//迭代加载,callback为全部加载完成后的回调函数
(function scriptRecurse(count, callback){
if(count == newScripts.length){
callback && callback();
}else{
loadScript(newScripts[count],function(){
document.getElementsByClassName('bubbleChart').innerHTML+=newScripts[count]+";<br>";
scriptRecurse(++count, callback);
});
}
})(0);
function loadScript(url, fn){
var script = document.createElement("script");
script.type ="text/javascript";
script.src = url;
script.onload = script.onreadystatechange =function(){
if(!script.readyState ||'loaded'=== script.readyState ||'complete'=== script.readyState){
fn && fn();
}
};
script.src = url;
document.head.appendChild(script);
}
},
js文件需要同步加载(按顺序),html中直接以CDN的形式引入script标签默认是以同步的方式加载,其余以插入元素的形式插入script标签的形式都是异步执行的(刷新会获得不同的效果以及错误),所以外部非es6js文件在vue引入必须进行阻塞实现同步渲染
Vue Jquery库推荐
- 粒子动态效果 vue-particles