1. Webpack集成Bootstrap
1.1 下载bootstrap3
npm i bootstrap3 -S
1.2 在index.js中引入bootstrap3
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
$(function() {
});
1.3 在index.html中使用bootstrap3中的样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" cnotallow="IE=edge">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
良辰美景奈何天,赏心乐事谁家院</h3>
<button class="btn btn-primary">Click me</button>
</body>
</html>
查看效果
2. Webpack集成Vue2.6
2.1 下载vue
npm i vue@2.6.12 -S
2.2 在index.js中引入vue
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
$(function() {
let app = new Vue({
el: "#app",
data: {
光年之外"
}
});
});
2.3 修改index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" cnotallow="IE=edge">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
{{msg}}
</div>
</body>
</html>
2.4 查看结果
启动webpack-dev-server,可以看到浏览器控制台报错了:
这是因为,我们在index.js中引入的vue资源,默认引入的是只能运行vue的环境,并不是开发vue的环境,如下图所示,默认引入的是runtime环境的资源:
为了解决这个问题,我们可以直接引入vue.min.js,如下:
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue/dist/vue.min.js'
$(function() {
let app = new Vue({
el: "#app",
data: {
光年之外"
}
});
});
查看效果
然而这种解决方法不优雅,下面使用一种更优雅的方式来解决这个问题,在webpack.config.js中加入以下配置来为vue定义别名:
修改webpack.config.js之后,要重启webpack-dev-server服务,然后在index.js中,引入vue资源:
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue' // 又改回 'vue' 这种写法了
$(function() {
let app = new Vue({
el: "#app",
data: {
光年之外"
}
});
});
查看效果
至此,Vue已经成功被webpack打包了。下面测试一下Vue中的组件开发。
2.5 在index.html中添加组件模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" cnotallow="IE=edge">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
</div>
<template id="t1">
<div>
原来姹紫嫣红开遍,似这般都付与断井颓垣。良辰美景奈何天,赏心乐事谁家院!
朝飞暮卷,云霞翠轩;雨丝风片,烟波画船——锦屏人忒看的这韶光贱!
</div>
</template>
</body>
</html>
2.6 在src/index.js中定义并注册组件
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
$(function() {
let myComponent = {
template: "#t1"
}
let app = new Vue({
el: "#app",
components: {
myComponent
}
});
});
查看效果
子组件也有自己的属性和方法,但是子组件和父组件,不能直接相互访问对方的属性和方法!
/*
以下引入了jquery资源,并且起了个名字叫 $
此后,在js代码中,但凡想使用jquery,就直接用 $ 就可以了
后面的资源路径,如果没有以 “.” 开头,则默认总是从node_modules开始寻找资源
后面的资源路径,如果确有以 “.” 开头,则就从当前路径开始寻找资源
*/
import $ from 'jquery'
import obj from '../data.json'
import './all.css'
import printMe from './print.js'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
/*
中接收一个函数,该函数就是一个回调函数,
该回调函数,会在页面加载完毕以后执行。
*/
$(function () {
let foo= {
"template": "#t1",
data() {
return {
刘德华",
"age": 62
}
},
methods: {
f2() {
console.log("zi.f2...");
}
}
}
let app = new Vue({
"el": "#app",
data: {
光年之外~~~"
},
methods: {
f1() {
console.log("fu.f1...");
}
},
注册子组件,注册到当前的app组件中,所以形成了父子组件的关系
是父组件, component是子组件
components: {
等价于 "foo": foo
}
})
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" cnotallow="IE=edge">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
父组件 -->
<div id="app">
{{msg}} <br>
点我</button>
<foo></foo>
</div>
子组件 -->
<template id="t1">
<div>
点点</button>
</div>
</template>
</body>
</html>
面试题:
Vue父子组件如何访问对方的属性和方法?
子组件如何访问父组件的属性:通过props属性。
子组件如何访问父组件的方法:通过 this.$emit()触发自定义事件
父组件如何访问子组件的属性:在子组件上添加一个ref属性,假设ref=xx, this.$refs.xx.属性
父组件如何访问子组件的方法:在子组件上添加一个ref属性,假设ref=xx, this.$refs.xx.方法
3. Webpack集成VueRouter
3.1 下载vue-router
npm i vue-router@3.5.3 -S
3.2 制作组件模板
在index.html中制作组件模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" cnotallow="IE=edge">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
<template id="t1">
<div>
<pre>
原来姹紫嫣红开遍,似这般都付与断井颓垣。良辰美景奈何天,赏心乐事谁家院!
朝飞暮卷,云霞翠轩;雨丝风片,烟波画船——锦屏人忒看的这韶光贱!
</pre>
</div>
</template>
</body>
</html>
3.2 导入路由模块
在index.js中导入路由模块,并使用
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
$(function() {
let myComponent = {
template: "#t1"
}
let router = new VueRouter({
routes: [
{ component: myComponent, path: '/myComponent'}
]
});
let app = new Vue({
el: "#app",
router
});
});
查看效果
4. 组件化开发
4.1 创建组件文件
在src目录下创建components目录,在其中创建App.vue
<template>
<div>
危楼高百尺,手可摘星辰。不敢高声语,恐惊天上人。
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
4.2 修改index.html
不用再在index.html编写任何组件的模板了,毕竟组件已经提取出来成为单独的文件了:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" cnotallow="IE=edge">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
</body>
</html>
4.3 引入App.vue
在src/index.js中引入App.vue,并使用
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
// 引入App组件
import App from './components/App.vue'
$(function() {
let router = new VueRouter({
routes: [
注册App组件到路由中
{ component: App, path: '/App'}
]
});
let app = new Vue({
el: "#app",
使用路由
router
});
});
(在webpack-dev-server开启的情况下)保存index.js时,会发现有报错信息:
这是因为webpack默认无法打包vue资源。为了让webpack能够打包vue资源,需要下载 vue-loader 和 vue-template-compiler。
4.4 让Webpack能打包Vue文件资源
npm i vue-loader@15.9.5 vue-template-compiler@2.6.12 -D
注意vue-template-compiler要与vue的版本一致,都是2.6.12
修改webpack.config.js中的module:
此时重新启动webpack-dev-server,还是会报错:
这是因为vue-loader从15+版本以后,配置方法有了变化,为了解决以上的问题,还需要在webpack.config.js中配置一个Plugin:
再次启动webpack-dev-server,发现没有报错:
查看效果:
4.5 优化
实际开发中,index.html中的<div id="app"></div>元素中不会编写任何内容,就连<router-view></router-view>元素也不用写,这个div通常会被App.vue这个组件重新渲染(代替)。
改写index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" cnotallow="IE=edge">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
这里只留下div,其中的 router-view元素已经被删除了 -->
<div id="app">
</div>
</body>
</html>
改写index.js
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import App from './components/App.vue'
$(function() {
let myComponent = {
template: "#t1"
}
let router = new VueRouter({
routes: [
{ component: App, path: '/App'}
]
});
let app = new Vue({
el: "#app",
函数的参数由Vue框架传入
该参数又是另外一个函数,参数的
名字可以自己随意指定,这里指定
为:createElement
render: function(createElement) {
函数接收一个组件作为参数
返回该组件的html表示形式
return createElement(App);
函数返回什么内容,那么什么内容就会把
中的<div id="app"></div>元素给替换掉!
},
router
});
});
查看效果:
4.6 简单开发
开发App.vue
<template>
<div>
小星星少儿托管平台 <br>
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
开发Login.vue
<template>
<div>
username: <input type="text"> <br>
password: <input type="text"> <br>
登录</button>
注册</button>
</div>
</template>
<script>
export default {
methods: {
login() {
console.log('login...');
},
regUI() {
this.$router.push("/Reg");
}
}
}
</script>
<style scoped>
</style>
开发Reg.vue
<template>
<div>
username: <input type="text"> <br>
password: <input type="text"> <br>
confirm: <input type="text"> <br>
注册</button>
返回</button>
</div>
</template>
<script>
export default {
methods: {
reg() {
console.log('reg...');
},
loginUI() {
this.$router.push("/Login");
}
}
}
</script>
<style scoped>
</style>
开发index.js
测试:
4.7 抽离路由模块
目前index.js的内容,有点太杂乱了,下面我们把路由模块从index.js中抽离出来。
在src下创建router.js文件,内容如下:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import Login from './components/Login.vue'
import Reg from './components/Reg.vue'
let router = new VueRouter({
routes: [
{ component: Login, path: '/'},
{ component: Login, path: '/Login'},
{ component: Reg, path: '/Reg'},
]
});
export default router
index.js的内容:
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
import router from './router.js'
import App from './components/App.vue'
$(function() {
let app = new Vue({
el: "#app",
render: function(createElement) {
return createElement(App);
},
router
});
});
注意,App.vue这个组件还是要留在index.js中的。
测试:
5. Webpack集成axios
5.1 下载axios
npm i axios@0.24.0 -S
5.2 导入axios
在index.js中导入axios
import $ from 'jquery'
import 'bootstrap3/dist/css/bootstrap.min.css'
import Vue from 'vue'
import router from './router.js'
import axios from 'axios'
// axios.defaults.baseURL = '配置请求前缀'
Vue.prototype.$axios = axios // 把axios挂载到Vue的原型上
import App from './components/App.vue'
$(function() {
let app = new Vue({
el: "#app",
render: function(createElement) {
return createElement(App);
},
router
});
});
5.3 使用
login() {
this.$axios.post("http://localhost:8080/users");
},
注意,使用axios发起ajax请求时,务必解决跨域问题,我们可以在后端解决跨域问题,如下:
axios的post等方法的第三个参数为配置对象,可以设置请求头的信息:
axios.post(url, data, config).then(...);
配置对象例子:
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
};
用于发送name=andy&age=22形式的数据,类型是字符串
const config2 = {
headers: {
"Content-Type": "application/json",
},
};
用于发送json形式的数据,类型是字符串
const config = {
headers: {
"Content-Type": "multipart/form-data",
},
};
用于文件上传,要搭配FormData一起使用,如下:
// id为file的元素是一个文件域
const fileElement = document.querySelector("#file");
const file = fileElement.files[0];
const formData = new FormData();
formData.append("file", file);
formData.append("filename", "filename...");
axios.post("/test", formData, config).then((resp) => {
this.$message({
type: "success",
message: resp.data,
});
});
注意,当我们使用axios传送一个FormData数据给后端时,此时的Content-Type请求头默认就是multipart/form-data
两个url是否同源,取决于以下3个部分: 协议、ip地址、端口号。
只要协议、ip地址、端口号都想用,才算作同源,有一个不相同,就算作不同源。
比如:
http://localhost:8080/1.html 和 http://localhost:8080/2.html 同源
http://localhost:8080/1.html 和 https://localhost:8080/1.html 不同源
http://127.0.01:8080/1.html 和 http://localhost:8080/1.html 不同源
http://localhost:8080/ 和 http://localhost:8888 不同源!
不同源的连个资源之间不能通信!
为了解决跨域问题,需要在后端添加配置:
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
/**
跨域配置
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
允许任意客户端访问
允许客户端用任意方式请求
允许客户端发送的请求中可以包含任意请求头
}
}
6. Webpack集成Element-UI
Element-UI官方网址: https://element.eleme.cn/#/zh-CN
6.1 安装
npm i element-ui -S
6.2 Element-UI Hello World
创建一个Vue组件:ElementUI.vue,在其中编写Element-UI的组件
在router.js中引入ElementUI.vue,并注册到路由器对象中:
在index.js中引入ElementUI:
查看效果:
6.4 Element-UI 布局+布局容器
<template>
<div>
<el-row>
<el-col :span="12" :offset="6">
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside>Aside</el-aside>
<el-main>Main</el-main>
</el-container>
<el-footer>Footer</el-footer>
</el-container>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data() {
return {
visible: false,
};
},
};
</script>
<style scoped>
.el-header,
.el-footer {
background-color: #b3c0d1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #d3dce6;
color: #333;
text-align: center;
line-height: 560px;
}
.el-main {
background-color: #e9eef3;
color: #333;
text-align: center;
line-height: 560px;
}
</style>
效果:
更多Element-UI组件的使用,就直接参照官方文档吧。
7. Webpack集成Vuex
Vue中的父子组件之间不能直接相互访问对方的属性和方法,非要互相访问,可以按照以下的方式进行:
1. 子组件方法父组件的属性: props: ["abc"] <Zi :abc="父组件的属性名" ></Zi>
2. 子组件方法父组件的方法: this.$emit("haha") <Zi @haha="父组件的方法"></Zi>
3. 父组件方法子组件的属性: a.给子组件添加一个ref="foo", b. 在父组件的方法中:this.$refs.foo.子组件属性
4. 父组件方法子组件的方法: a.给子组件添加一个ref="foo", b. 在父组件的方法中:this.$refs.foo.子组件方法
我们已经知道,Vue中的父子组件之间不能直接相互访问对方的属性和方法。如果非要让父子组件之间能够访问对方的属性和方法,会很麻烦,尤其是嵌套多层的父子组件。如下:
为了简化父子组件之间相互访问难的问题,Vuex就应运而生了:
7.1 安装Vuex
npm i vuex@3.5.1 -s
7.2 store.js
在src下创建store.js
7.3 引入
在index.js中引入store.js,并使用:
在父组件中引入store之后,该父组件下的所有子组件就都能访问到store中的数据了
7.4 使用
创建Foo组件
创建Bar组件
在路由模块中引入:
查看效果:(测试时,必须在同一个窗口之内,否则Vuex中存储的状态无法共享)
7.5 改变需求
现在需要在Foo和Bar组件中,显示count属性的前后,加上“[ ]”,这需要使用Vuex对象中的getters。修改store.js
修改Foo.vue(Bar.vue也是这样改)
查看效果(必须在同一个页面中测试,否则无法共享Vuex对象中的数据)
8. Webpack集成zTree
zTree官网: http://www.treejs.cn/v3/main.php#_zTreeInfo
8.1 下载ztree
npm i ztree -s
8.2 引入
因为ztree是基于jQuery的,所以我们需要先导入jquery,再导入ztree
npm i jquery -s
import $ from 'jquery'
import 'ztree'
import 'ztree/css/zTreeStyle/zTreeStyle.css'
但是浏览器会报错,说ztree找不到jQuery:
这是因为,ztree依赖于jQuery,而我们在代码中 import $ from 'jquery' 是不够的,这仅仅只是解决了我们自己的代码对jQuery的依赖。
解决方案:针对于自己手动创建的前端项目,在webpack.config.js的顶部引入webpack插件
const webpack = require('webpack')
然后在plugins中配置:
plugins: [
new HtmlWebpackPlugin({
title: 'test...',
template: './index.html'
}),
new CleanWebpackPlugin(),
new VueLoaderPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jquery: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
],
解决方案:针对于脚手架vue cli3,要在项目根目录下创建vue.config.js,配置内容如下:
const webpack = require('webpack')
module.exports = {
chainWebpack: config => {
config.plugin('provide').use(webpack.ProvidePlugin, [{
$: 'jquery',
jquery: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}])
}
}
8.3 标准json构建ztree
demo1
<div>
<ul id="basicTree" class="ztree"></ul>
</div>
// 设置参数
let settings = {};
// 设置树的数据
let nodes = [
菜单一"},
菜单二"}
]
// 初始化树
$.fn.zTree.init($("#basicTree"), settings, nodes);
demo2
<ul id="basicTree" class="ztree"></ul>
// 设置参数
let settings = {};
// 设置树的数据
let nodes = [
菜单一"},
菜单二", children:[
菜单二-1"},
菜单二-2"},
菜单二-3"}
]}
]
// 初始化树
$.fn.zTree.init($("#basicTree"), settings, nodes);
8.4 简单数据构建ztree(推荐)
demo
<ul id="basicTree" class="ztree"></ul>
// 设置参数
let settings = {
data: {
simpleData: {
启用简单树
}
}
};
// 设置树的数据
let nodes = [
菜单一"},
菜单二"},
菜单一-1"},
菜单一-2"},
]
// 初始化树
$.fn.zTree.init($("#basicTree"), settings, nodes);
8.5 定制
可以手动指定idKey、pIdkey、name对应的json属性,如下:
// 设置参数
let settings = {
data: {
key: {
name: "pname"
},
simpleData: {
启用简单树
idKey: "pid",
pIdKey: "parent"
}
}
};
// 设置树的数据
let nodes = response.data.data;
// 初始化树
$.fn.zTree.init($("#basicTree"), settings, nodes);