文章目录
vue
1.mvvm模型浅谈
- mvvm模型指的是:model(模型) view(视图) viewmodel(视图模型层)
MVVM 的核心是 ViewModel 层,负责转 换 Model 中的数据对象来让数据变得更容易管理和使用,其作用如下: 该层向上与视图层进行双向数据绑定 向下与 Model 层通过接口请求进行数据交互 。
MVVM 已经相当成熟了,当下流行的 MVVM 框架有 Vue.js , AngularJS 等。
- mvvm和mvc十分相似,它们都分离了model 和 view ,他们都具有以下优点:
- 低耦合: 视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的 View 上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
- 可复用: 你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 View 重用这段视图逻辑。
- 独立开发: 开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页 面设计。
- 可测试: 界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。
1.1.mvvm的模型
-
View: View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建,为了更方便地展现 ViewModel 或者 Model层的数据,已经产生了各种各样的前后端模板语言,比如 FreeMarker、 Thymeleaf 等等,各大 MVVM 框架如 Vue.js,AngularJS,EJS 等也都有自己用来构建用户界面的内置 模板语言。
-
Model: Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。这里 的难点主要在于需要和前端约定统一的 接口规则 ViewModel:
-
ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。
View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方 案实施的重要一环。
1.2.关于双向绑定和虚拟dom的个人理解
- 双向绑定:指的是view层和viewmodel层的双向绑定,因为有了双向绑定,使得viewmodel层可以直接操作view层,view层的操作也会第一时间反馈到viewmodel层,使得用户的交互可以在不刷新页面的前提下,改变model层,使得网页加载更快,提高加载效率。
- 虚拟dom:虚拟dom指的是在页面中的数据是动态的,是viewmodel控制的动态数据,可以通过viewmodel在不刷新页面的前提下改变。也就是说页面展示的dom都是可以随时改变的,没有固定的实际值,所以被称为虚拟dom。
1.3.vue的生命周期
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 DOM、渲染→更 新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过 程,就是生命周期。 在 Vue 的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册 JS 方法,可以让我们 用自己注册的 JS 方法控制整个大局,在这些事件响应方法中的 this 直接指向的是 Vue 的实例。
2.第一个vue程序和环境搭建
2.1.环境搭建
-
idea
去插件里(plugin)下载 vue.js
-
vscode
$ npm install vue
-
cdn
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js">
</script>
2.2.hello vue!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层-->
<div id="vue">{{message}}</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<!--model层-->
<script type="text/javascript">
var vm = new Vue({
el: '#vue',
data: {
message: 'Hello Vue!'
}
});
</script>
</body>
</html>
在console里可以使用viewmodel层。
例如:vm.message=“sss”
页面显示的就会由 hello vue变成 sss。
3.vue一些基础语法
3.1.v-bind
<body>
<div id="app">
<h1 v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</h1>
<!-- v-bind 指令的简写形式: 冒号(:) -->
<h1 :title="message">我是标题</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
new Vue({
el: '#app',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
</script>
</body>
3.2.v-if 系列
<body>
<div id="app">
<h1 v-if="type === 'A'">A</h1>
<h1 v-else-if="type === 'B'">B</h1>
<h1 v-else-if="type === 'C'">C</h1>
<h1 v-else>who</h1>
<h1 v-if="ok">1</h1>
<h1 v-else>0</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
ok:true,
type: 'A'
}
})
</script>
</body>
3.3.v-for
<body>
<div id="app">
<li v-for="item in items">
{{ item.message }}
</li>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
//items数组
items: [
{message: '狂神说Java'},
{message: '狂神说前端'}
]
}
});
</script>
</body>]()
<body>
<div id="app">
<li v-for="(item,index) in items">
{{ item.message }} {{index}}
</li>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
//items数组
items: [
{message: '狂神说Java'},
{message: '狂神说前端'}
]
}
});
</script>
</body>
3.4.v-on
<body>
<div id="app">
<button v-on:click="sayHi">点我</button>
<!-- v-on 指令的简写形式 @ -->
<button @click="sayHi">点我</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello World'
},
// 方法必须定义在 Vue 实例的 methods 对象中
methods: {
sayHi: function (event) {
// `this` 在方法里指向当前 Vue 实例
alert(this.message);
}
}
});
</script>
</body>
3.5.v-model(双向绑定)
文本框
<body>
<div id="app">
<!-- v-bind:value只能进行单向的数据渲染 -->
<input type="text" v-bind:value="searchMap.keyWord">
<!-- v-model 可以进行双向的数据绑定 -->
<input type="text" v-model="searchMap.keyWord">
<p>您要查询的是:{{searchMap.keyWord}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
new Vue({
el: '#app',
data: {
searchMap:{
keyWord: 'kuangshen'
}
}
})
</script>
</body>
单复选框
<body>
<div id="app">
单复选框:
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
new Vue({
el: '#app',
data: {
checked: false
}
})
</script>
</body>
多复选框
<body>
<div id="app">
多复选框:
<input type="checkbox" id="jack" value="Jack" vmodel="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" vmodel="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" vmodel="checkedNames">
<label for="mike">Mike</label>
<span>选中的值: {{ checkedNames }}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
new Vue({
el: '#app',
data: {
checkedNames: []
}
})
</script>
</body>
单选按钮
<body>
<div id="app">
单选按钮:
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<span>选中的值: {{ picked }}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
new Vue({
el: '#app',
data: {
picked: ''
}
})
</script>
</body>
下拉框
<body>
<div id="app">
下拉框:
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>选中的值: {{ selected }}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
selected: ''
}
});
</script>
</body>
注意:v-model默认会把绑定的数据变成字符串,当我们需要它为数字时,需要写v-model.number
<input type="text" v-model.number="b">{{b}}
实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model.number="a">{{a}}
<input type="text" v-model.number="b">{{b}}
<input type="text" v-model="sum">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
a:1,
b:2
},
computed:{
sum:{
get(){
return this.a+this.b;
},
set(value){
this.a=value/2;
this.b=value/2;
}
}
}
});
</script>
</body>
</html>
4.vue的组件
4.1.组件
- 简单来说就是自定义一套模板,以标签的形式表示。
往组件里传参数的方法
<body>
<div id="app">
<ul>
<my-component-li v-for="item in items" v-bind:it="item">
</my-component-li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
// 先注册组件
Vue.component('my-component-li', {
props: ['it'],
template: '<li>Hello {{it}}</li>'
});
// 再实例化 Vue
var vm = new Vue({
el: '#app',
data: {
items: ["张三", "李四", "王五"]
}
});
</script>
</body>
props中是先定义好变量名字再由标签里面来给这些变量赋值,最后在组件里调用,且组件只能调用props里的值。
注意:prop里的值不能为大写!!
5.计算属性
5.1.计算属性
-
vue里的computed是特殊的函数,它是写成函数形式的一种属性,本质上运用了缓存的原理。也就是说同类运算二次使用的时候将不再次运算,使得效率更高。
下面是例子!!
<body>
<div id="app">
<!--注意,一个是方法,一个是属性-->
<p>调用当前时间的方法:{{currentTime1()}}</p>
<p>当前时间的计算属性:{{currentTime2}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vue = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
methods: {
currentTime1: function () {
return Date.now();
}
},
computed: {
//currentTime2 ,这是一个属性!不是方法
currentTime2: function () {
this.message;
return Date.now();
}
}
})
</script>
</body>
注意:computed声明的时候尽量不要和methods里的方法重名。
计算属性的getter和setter
一般,计算属性会默认调用getter方法,当双向绑定元素是input的时候,输入sum时会调用setter方法.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model.number="a">{{a}}
<input type="text" v-model.number="b">{{b}}
<input type="text" v-model="sum">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
a:1,
b:2
},
method:{
},
computed:{
sum:{
get(){
return this.a+this.b;
},
set(value){
this.a=value/2;
this.b=value/2;
}
}
}
});
</script>
</body>
</html>
5.2.监听器
监听器会持续监听绑定的元素,每当绑定的元素发生变化,监听器里的函数都会触发。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="see">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">
</script>
<script>
var vm = new Vue({
el: '#app',
data: {
see:""
},
method:{
},
watch:{
see(){
console.log("你在被我监视着。。。。。。。")
}
}
});
</script>
</body>
</html>
注意:监听器使用的时候,data里必须有和监听器函数同名的变量。如上面see
-
监听器还可以获取没改动之前的数据和改动后的数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <input type="text" v-model="see"> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"> </script> <script> var vm = new Vue({ el: '#app', data: { see:22 }, method:{ }, watch:{ see(oldData,newData){ console.log("老的数据为:"+oldData+"新的数据为:"+newData); } } }); </script> </body> </html>
6.插槽
插槽是一种自定义标签模板的方式。
<div id="app">
<todo>
<todo-title slot="todo-title" title="秦老师系列课程"></todo-title>
<todo-items slot="todo-items" v-for="(item, index) in todoItems"
v-bind:item="item" v-bind:index="index"></todo-items>
</todo>
</div>
<script type="text/javascript">
Vue.component('todo', {
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component('todo-title', {
props: ['title'],
template: '<div>{{title}}</div>'
});
Vue.component('todo-items', {
props: ['item', 'index'],
template: '<li>{{index + 1}}. {{item}}</li>'
});
new Vue({
el: '#app',
data: {
todoItems: ['狂神说Java', '狂神说运维', '狂神说前端']
}
})
</script>
- 注意:/ 等同于换行!!
//1
Vue.component('todo', {
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
等同于
//2
Vue.component('todo', {
template: '<div>'
'<slot name="todo-title"></slot>'
'<ul>'
'<slot name="todo-items"></slot>'
'</ul>'
'</div>'
});
7.自定义事件(组件操作实例化对象里的函数)
<!--增加了 v-on:remove="removeTodoItems(index)" 自定义事件,该事件会调用 Vue 实例中
定义的名为 removeTodoItems 的方法-->
<todo-items slot="todo-items" v-for="(item, index) in todoItems"
v-bind:item="item" v-bind:index="index"
v-on:remove="removeTodoItems(index)"></todo-items>
new Vue({
el: '#app',
data: {
todoItems: ['狂神说Java', '狂神说运维', '狂神说前端']
},
methods: {
// 该方法可以被模板中自定义事件触发
removeTodoItems: function (index) {
console.log("删除 " + this.todoItems[index] + " 成功");
// splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目
// 其中 index 为添加/删除项目的位置,1 表示删除的数量
this.todoItems.splice(index, 1);
}
}
})
Vue.component('todo-items', {
props: ['item', 'index'],
template: '<li>{{index + 1}}. {{item}} <button
@click="remove_component">删除</button></li>',
methods: {
remove_component: function (index) {
// 这里的 remove 是自定义事件的名称,需要在 HTML 中使用 v-on:remove 的
方式指派
this.$emit('remove', index);
}
}
});
8.vue-cli
什么是vue-cli
vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板
8.1.环境配置
1.npm导入vue-cli
npm i vue-cli -g
2.在项目目录下启动cmd,输入以下代码创建项目
vue init webpack 项目名字
3.编译环境初始化
npm i
出现这个毛病的时候按照nodejs提示运行代码就行!
npm audit fix
4.运行项目
-
打开创建好的项目文件夹,运行下面指令
npm run dev
5.项目停止
- 上面启动页面输入 ctrl+c
vue-cli初始文件的结构和作用
Vue-cli目录结构
build 和 config:WebPack 配置文件
node_modules:用于存放 npm install 安装的依赖文件
src: 项目源码目录
static:静态资源文件
.babelrc:Babel 配置文件,主要作用是将 ES6 转换为 ES5
.editorconfig:编辑器配置
eslintignore:需要忽略的语法检查配置文件
.gitignore:git 忽略的配置文件
.postcssrc.js:css 相关配置文件,其中内部的 module.exports 是 NodeJS 模块化语法
index.html:首页,仅作为模板页,实际开发时不使用
package.json:项目的配置文件
name:项目名称
version:项目版本
description:项目描述
author:项目作者
scripts:封装常用命令
dependencies:生产环境依赖
devDependencies:开发环境依赖
src目录
源码的存放地
main.js
/ The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an
alias.
import Vue from 'vue'//把module里的vue组件导入
import App from './App'//自己定义的App.vue导入
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>'
});
import Vue from 'vue' :ES6 写法,会被转换成 require("vue"); (require 是 NodeJS 提供
的模块加载器)
import App from './App' :意思同上,但是指定了查找路径,./ 为当前目录
Vue.config.productionTip = false :关闭浏览器控制台关于环境的相关提示
new Vue({...}) :实例化 Vue
el: '#app' :查找 index.html 中 id 为 app 的元素
template: '' :模板,会将 index.html 中
替换为
components: { App } :引入组件,使用的是 import App from './App' 定义的 App 组
件;
App.vue
template>
<div id="app">
<img src="./assets/logo.png">
<HelloWorld/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
- template:HTML 代码模板,会替换 < App /> 中的内容
- import HelloWorld from ‘./components/HelloWorld’:引入 HelloWorld 组件用于替换 template
中的 < HelloWorld/> - export default{…}:导出 NodeJS 对象,作用是可以通过 import 关键字导入
name: ‘App’:定义组件的名称 - components: { HelloWorld }:定义子组件
在hello,Vue中,关于 < style scoped> 的说明:CSS 样式仅在当前组件有效,声明了样式的作用域,
是当前的界面私有的!
9.webpack
webpack是什么
- webpack是一种打包方式,它可以把es6的代码打包成es5的代码
对exports的深入理解
webpack的基本使用
1.导入环境
npm i webpack
npm i webpack-cli
2.实例
- 结构如下
-
hello.js
exports.hello1=function (){ document.write("<h1>大撒大撒</h1>"); } //让这个方法暴露成一个接口
-
main.js
let hello=require("./hello");//接收hello这个js文件 hello.hello1();//使用这个js文件已经暴露接口的函数
-
webpack.config.js
module.exports={ entry:'./modules/main.js',//选择你要打包的文件 output:{ filename:"./js/bundle.js"//要打包成的形式 } }
注意:打包完main.js后,mainjs导入的东西也会被打包进去!
10.Vue-router
10.1.环境的搭建
1.创建一个vue-cli模板(见vue-cli)
2.导入
npm install vue-router --save-dev
10.2.实例
- 目录
- App.vue
<template>
<div id="app">
<h1>Router</h1>
<router-link to="/main">首页</router-link>
<router-link to="/content">内容页</router-link>
<!-- 通过这个将的到页面渲染到下面-->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
-
main.js
import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
-
index.js
import Vue from 'vue'
import VueRouter from "vue-router"
import Content from "../components/Content"
import Main from "../components/Main"
Vue.use(VueRouter);
//new的那个必须和use的一样
export default new VueRouter({
routes:[
//name可写可不写
{path:'/content',name:'content',component:Content},
{path:'/main',name:'main',component:Main}
]
});
-
Content.vue
<template> <h1>内容页</h1> </template> <script> export default { name: "Content" } </script> <style scoped> </style>
-
main.vue
<template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <!--下面的只对该组件内的模板有效--> <style scoped> h1{ color: aqua; } </style>
10.3.路由嵌套
-
目录结构
-
index.js
import Vue from 'vue' import VueRouter from "vue-router" import Content from "../components/Content" import Main from "../components/Main" Vue.use(VueRouter); //new的那个必须和use的一样 export default new VueRouter({ routes:[ //name可写可不写 {path:'/content',name:'content',component:Content}, {path:'/main',name:'main',component:Main} ] });
-
Content.vue(非重要)
<template> <div> <el-row> <el-col :span="24"><div class="grid-content bg-purple-dark"></div></el-col> </el-row> <el-row> <el-col :span="12"><div class="grid-content bg-purple"></div></el-col> <el-col :span="12"><div class="grid-content bg-purple-light"></div></el-col> </el-row> <el-row> <el-col :span="8"><div class="grid-content bg-purple"></div></el-col> <el-col :span="8"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="8"><div class="grid-content bg-purple"></div></el-col> </el-row> <el-row> <el-col :span="6"><div class="grid-content bg-purple"></div></el-col> <el-col :span="6"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="6"><div class="grid-content bg-purple"></div></el-col> <el-col :span="6"><div class="grid-content bg-purple-light"></div></el-col> </el-row> <el-row> <el-col :span="4"><div class="grid-content bg-purple"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple-light"></div></el-col> </el-row> </div> </template> <script> export default { data: () => ({ show3: true }) } </script> <style> .el-row { margin-bottom: 20px; &:last-child { margin-bottom: 0; } } .el-col { border-radius: 4px; } .bg-purple-dark { background: #99a9bf; } .bg-purple { background: #d3dce6; } .bg-purple-light { background: #e5e9f2; } .grid-content { border-radius: 4px; min-height: 36px; } .row-bg { padding: 10px 0; background-color: #f9fafc; } </style>
-
Main.vue(重要)
<template> <!--注意:必须有div--> <div> <h1>我是主页</h1> <router-link to="/child/child">我是嵌套路由</router-link> <router-view></router-view> </div> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
App.vue
<template> <div id="app"> <img src="./assets/logo.png"> <h1>欢迎来到路由页面</h1> <router-link to="/content">content</router-link> <router-link to="/main">first</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: blanchedalmond; margin-top: 60px; } </style>
-
main.js
import Vue from 'vue'; //ElementUI的引入 import ElementUI的引入 from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App'; import Router from './router'; Vue.config.productionTip = false //使用 Vue.use(ElementUI); new Vue({ el: '#app', router:Router, components: { App }, template: '<App/>', render: h => h(App) })
-
child.vue
<template> <h1>我是嵌套路由</h1> </template> <script> export default { name: "child" } </script> <style scoped> </style>
10.4.参数传递
10.4.1.第一种方法
-
index.js
import Vue from 'vue' import VueRouter from "vue-router" import Main from "../components/Main" import ch from "../child/child" Vue.use(VueRouter); export default new VueRouter({ routes:[ {path:'/main',name:'main',component:Main, //注意传参方法:':/id' children:[{path:'/child/child/:id',name:'child',component:ch}]} ] });
-
Main.vue
<template> <div> <h1>我是主页</h1>params <!--跳转的链接接受参数 注意bind绑定 params--> <router-link :to="{name:'child',params:{id:1}}">我是嵌套路由</router-link> <router-view></router-view> </div> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
child.vue
<template> <div> <h1>我是嵌套路由</h1> //参数的使用 {{$route.params.id}} </div> </template> <script> export default { name: "child" } </script> <style scoped> </style>
-
App.vue
<template> <div id="app"> <img src="./assets/logo.png"> <h1>欢迎来到路由页面</h1> <router-link to="/main">first</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: blanchedalmond; margin-top: 60px; } </style>
-
Main.js
import Vue from 'vue'; import App from './App'; import Router from './router'; Vue.config.productionTip = false new Vue({ el: '#app', router:Router, components: { App }, template: '<App/>', })
10.4.2.第二种传递方式(用props)
修改上面这两项:
- child.vue
<template>
<div>
<h1>我是嵌套路由</h1>
{{id}}
</div>
</template>
<script>
export default {
props:['id'],
name: "child"
}
</script>
<style scoped>
</style>
-
index.js
import Vue from 'vue' import VueRouter from "vue-router" import Main from "../components/Main" import ch from "../child/child" Vue.use(VueRouter); export default new VueRouter({ routes:[ {path:'/main',name:'main',component:Main,children:[{path:'/child/child/:id',name:'child',component:ch,props:true}]} ] });
10.5.重定向
-
index.js
import Vue from 'vue' import VueRouter from "vue-router" import Main from "../components/Main" import ch from "../child/child" import ref from "../components/refined" Vue.use(VueRouter); //new的那个必须和use的一样 export default new VueRouter({ routes:[ //name可写可不写js {path:'/main',name:'main',component:Main,children:[{path:'/child/child/:id',name:'child',component:ch,props:true}]} //重定向的方法和重定向后的页面 ,{path:'/re',redirect:'/refined'}, {path:'/refined',component:ref} ] });
-
Main.vue
<template> <div class="b"> <h1>我是主页</h1> <router-link :to="{name:'child',params:{id:1}}">我是嵌套路由</router-link> <router-view></router-view> </div> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
child.vue
<template> <div> <h1>我是嵌套路由</h1> {{id}} </div> </template> <script> export default { props:['id'], name: "child" } </script> <style scoped> </style>
-
App.vue
<template> <div id="app"> <img src="./assets/logo.png"> <h1>欢迎来到路由页面</h1> <router-link to="/main">first</router-link> <router-link to="/re">re</router-link> <div class="b"> <router-view></router-view> </div> </div> </template> <script> export default { name: 'App', components: { } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: blanchedalmond; margin-top: 60px; } .b{ width: 1000px; height: 500px; border: black 1px solid; margin: 0 auto; } </style>
-
main.js
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App'; import Router from './router'; Vue.config.productionTip = false Vue.use(ElementUI); new Vue({ el: '#app', router:Router, components: { App }, template: '<App/>', render: h => h(App) })
10.6.#去掉
10.6.表单提交
项目结构
-
App.vue
<template> <div id="app"> <img src="./assets/logo.png"> <h1>欢迎来到路由页面</h1> <router-link to="/main">first</router-link> <div class="b"> <router-view></router-view> </div> </div> </template> <script> export default { name: 'App', components: { } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: blanchedalmond; margin-top: 60px; } .b{ width: 1000px; height: 500px; border: black 1px solid; margin: 0 auto; } </style>
-
refined.vue
<template> <div> <h1>re</h1> <!-- <h1>{{name}}</h1>--> {{this.$route.params.name}} </div> </template> <script> export default { name: "refined", // props:['name'] } </script> <style scoped> </style>
-
Main.vue
<template> <div class="b"> <h1>我是主页</h1> <form> <input type="text" name="name" v-model="username"/>姓名 <button @click="tr">点我</button> <!-- 名字要和路由文件里注册的名字相同--> <!-- <router-link :to="refined">表单跳转</router-link>--> </form> <router-view></router-view> </div> </template> <script> export default { name: "Main", data(){return{ username: "请输入姓名" } } , methods:{ tr:function (){ //把表单上的数据传到地址栏上去 注意这里是router 注意这个form不是页面上的 而是vue实例化对象里的 this.$router.push({name:"ref",params:{name:this.username}}); console.log(this.username); } } } </script> <style scoped> </style>
-
index.js
import Vue from 'vue' import VueRouter from "vue-router" import Main from "../components/Main" import ch from "../child/child" import ref from "../components/refined" import axi from "../components/axi" Vue.use(VueRouter); export default new VueRouter({ mode:"history", routes:[ {path:'/main',component:Main,props:"true"}, //注意这里要写上true // 始终都是要传递的页面的路由上写上参数 {path:'/refined/:name',name:"ref",component:ref,props:"true"}, ] });
-
main.js
import Vue from 'vue'; import App from './App'; import Router from './router'; Vue.use(Router) Vue.config.productionTip = false new Vue({ el: '#app', router:Router, components: { App }, template: '<App/>', render: h => h(App) }) import Vue from 'vue';
import ElementUI from ‘element-ui’;
import ‘element-ui/lib/theme-chalk/index.css’;
import App from ‘./App’;
import Router from ‘./router’;
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
el: ‘#app’,
router:Router,
components: { App },
template: ‘’,
render: h => h(App)
})
> 1.直接提交
上面实例不用改,关注这两个点:
- mode换成history
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-38TbhNuT-1618369063770)(D:\studyNode\img\vue\QQ截图20210411120829.png)\]](https://img-blog.csdnimg.cn/20210414110634497.png)
- 写个表单就行了
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FlfZzQcW-1618369063770)(D:\studyNode\img\vue\QQ截图20210411120937.png)\]](https://img-blog.csdnimg.cn/20210414110639394.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FiYWlkYXll,size_16,color_FFFFFF,t_70)
### 10.7.axios和钩子函数
#### 10.7.1.axios
> 导入
```npm
npm install --save vue-axios
main.js里面
import axios from 'axios'
import vueaxios from 'vue-axios'
Vue.use(axios,vueaxios)
10.7.2.钩子函数
- 在一个组件里
<template>
<h1>axios</h1>
</template>
<script>
export default {
name: "axi",
beforeRouteEnter:(to,from,next)=>{
console.log("进入路由器前。。。。。。");
next(vm => {
});
},
beforeRouteLeave:(to,from,next)=>{
console.log("进入路由后。。。。");
next();
},
}
</script>
<style scoped>
</style>
注意:钩子函数有很多,穿插在整个vue周期里,上面的只是类似拦截器的
10.7.3.二者结合起来使用
项目目录如下
-
index.js
import Vue from 'vue' import VueRouter from "vue-router" import Main from "../components/Main" import ch from "../child/child" import ref from "../components/refined" import axi from "../components/axi" Vue.use(VueRouter); export default new VueRouter({ mode:"history", routes:[ {path:'/main',component:Main,props:"true"} {path:'/axi',component:axi} ] });
-
data.json
{ "name": "dadadad" }
-
App.vue
<template> <div id="app"> <img src="./assets/logo.png"> <h1>欢迎来到路由页面</h1> <router-link to="/axi">ax</router-link> <div class="b"> <router-view></router-view> </div> </div> </template> <script> export default { name: 'App', components: { } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: blanchedalmond; margin-top: 60px; } .b{ width: 1000px; height: 500px; border: black 1px solid; margin: 0 auto; } </style>
-
axi.vue
<template> <h1>axios</h1> </template> <script> export default { name: "axi", beforeRouteEnter:(to,from,next)=>{ console.log("进入路由器前。。。。。。"); next(vm => { vm.getData(); }); }, beforeRouteLeave:(to,from,next)=>{ console.log("进入路由后。。。。"); next(); }, methods:{ getData:function (){ thisvue.axios({ method:"get", url:'http://localhost:8080/static/mock/data.json' }).then(function (res){ console.log(res); }) } } } </script> <style scoped> </style>
-
main.js
import Vue from 'vue'; import App from './App'; import Router from './router'; //axios import axios from 'axios' import vueaxios from 'vue-axios' Vue.use(axios,vueaxios) // Vue.use(Router) Vue.config.productionTip = false new Vue({ el: '#app', router:Router, components: { App }, template: '<App/>', render: h => h(App) })
11.ElementUI与vue
11.1.环境搭建
在所选文件夹里打开cmd
1.搭建webpack项目
vue init webpack 项目名
2.cd +项目名 //切到对应项目里
3.安装vue-router
npm install vue-router ---save-dev
4.安装element-ui
npm i element-ui -s
5.安装依赖
npm install
6.安装 SASS加载器
cnpm install sass-loader node-sass --save-dev
7.启动测试
npm run dev
-S 等同于npm install module_name --save 写入依赖,项目打包发布后最终用到的 -D 等同于npm install module_name --save-dev 写入开发依赖,开发期间用到的,最终打包时不添加到项目包中。
11.2.实例
- 目录结构
-
index.js
import Vue from 'vue' import VueRouter from "vue-router" import Content from "../components/Content" import Main from "../components/Main" Vue.use(VueRouter); //new的那个必须和use的一样 export default new VueRouter({ routes:[ //name可写可不写 {path:'/content',name:'content',component:Content}, {path:'/main',name:'main',component:Main} ] });
-
Content.vue
<template> <div> <el-row> <el-col :span="24"><div class="grid-content bg-purple-dark"></div></el-col> </el-row> <el-row> <el-col :span="12"><div class="grid-content bg-purple"></div></el-col> <el-col :span="12"><div class="grid-content bg-purple-light"></div></el-col> </el-row> <el-row> <el-col :span="8"><div class="grid-content bg-purple"></div></el-col> <el-col :span="8"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="8"><div class="grid-content bg-purple"></div></el-col> </el-row> <el-row> <el-col :span="6"><div class="grid-content bg-purple"></div></el-col> <el-col :span="6"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="6"><div class="grid-content bg-purple"></div></el-col> <el-col :span="6"><div class="grid-content bg-purple-light"></div></el-col> </el-row> <el-row> <el-col :span="4"><div class="grid-content bg-purple"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple-light"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple"></div></el-col> <el-col :span="4"><div class="grid-content bg-purple-light"></div></el-col> </el-row> </div> </template> <script> export default { data: () => ({ show3: true }) } </script> <style> .el-row { margin-bottom: 20px; &:last-child { margin-bottom: 0; } } .el-col { border-radius: 4px; } .bg-purple-dark { background: #99a9bf; } .bg-purple { background: #d3dce6; } .bg-purple-light { background: #e5e9f2; } .grid-content { border-radius: 4px; min-height: 36px; } .row-bg { padding: 10px 0; background-color: #f9fafc; } </style>
-
Main.vue
<template> <h1>我是主页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
App.vue
<template> <div id="app"> <img src="./assets/logo.png"> <h1>欢迎来到路由页面</h1> <router-link to="/content">content</router-link> <router-link to="/main">first</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: blanchedalmond; margin-top: 60px; } </style>
-
main.js
import Vue from 'vue'; //ElementUI的引入 import ElementUI的引入 from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App'; import Router from './router'; Vue.config.productionTip = false //使用 Vue.use(ElementUI); new Vue({ el: '#app', router:Router, components: { App }, template: '<App/>', render: h => h(App) })
注意:导入Element时候必须加入一个div把他框起来!!
id-content bg-purple">
- Main.vue
```js
<template>
<h1>我是主页</h1>
</template>
<script>
export default {
name: "Main"
}
</script>
<style scoped>
</style>
-
App.vue
<template> <div id="app"> <img src="./assets/logo.png"> <h1>欢迎来到路由页面</h1> <router-link to="/content">content</router-link> <router-link to="/main">first</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: blanchedalmond; margin-top: 60px; } </style>
-
main.js
import Vue from 'vue'; //ElementUI的引入 import ElementUI的引入 from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App'; import Router from './router'; Vue.config.productionTip = false //使用 Vue.use(ElementUI); new Vue({ el: '#app', router:Router, components: { App }, template: '<App/>', render: h => h(App) })
注意:导入Element时候必须加入一个div把他框起来!!
12.vue的常见错误
12.1.路由方面的错误
VueRouter Error in render: “TypeError: Cannot read property ‘resolve’ of undefined”
- 检查main.js里的路由引没引用
- Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
- 嵌套路由的时候,被嵌套的vue组件里根不唯一,没加div框起来。
文章是看了b站的秦疆老师(b站名称:狂神说)的课程总结出的自己的笔记和体会。秦疆老师的B站主页:https://space.bilibili.com/95256449/ 讲的超级好,想多学点的朋友可以看看秦疆老师的视频。