VUE
- 概述
- 一.新建一个VUE项目
- 二.VUE基本语法
- 三、vue的生命周期
- 四、vue路由:点击菜单栏显示不同的子页面(重点)
- 五.vue的网络通信Axios(超级重点、难点)
- 六、vuex的使用
- 七、element-ui:快速页面布局
- 八、node.js:javascript的运行环境
- 九、npm:node.js的包管理工具
- 十、babel转码器:把es6代码转换成es5
- 十一、模块化:实现js文件与js文件之间之间方法的调用
- 十二、webpack
概述
1.VUE是什么?为什么要学VUE
VUE是一个MVVM框架,即数据双向绑定,数据和视图会同时发生变化
一.新建一个VUE项目
1.1idea上使用vue
(1)在IDEA上安装一个vue.js插件
在setting中安装Vue.js插件
(2)新建一个html文件并引入VUE的cdn,引入cdn的语法如下。
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
(3)使用vue对象绑定标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--{{xxx}}来绑定文本 -->
<div id="app">
{{message}}
</div>
<!-- 1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- 2.使用一个vue对象绑定标签-->
<script>
var vm=new Vue({
el:"#app",
data:{
message:"hello.vue!"
}
});
</script>
</body>
</html>
(4)查看结果:实现了使用data内的属性替换html中的文本的效果
1.2VScode上使用vue
(1)创建html文件,并引入VUE的cdn
VScode中!+enter能够创建html的架构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
</body>
</html>
(2)使用一个vue对象绑定一个标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div class="app">
{{message}}
</div>
<script>
var vm=new Vue({
el:".app",
data:{
message:"hello.vue!"
}
});
</script>
</body>
</html>
(3)测试
【VScode的小技巧】:使用代码片段
4.1
文件
->首选项
->用户片段
->新建全局代码片段文件
:xxx.code-snippets
(后缀要正确)
4.2
{
"vue":{
"scope": "html",
"prefix": "vuehtml",//
"body": [
"<!DOCTYPE html>",
"<html lang=\"en\">",
"",
"<head>",
" <meta charset=\"UTF-8\">",
" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">",
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
" <title>Document</title>",
" <script src=\"https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js\"></script>",
"</head>",
"<body>",
" <div class=\"app\">",
" {{message}}",
"</div>",
"",
" <script>",
" var vm=new Vue({",
" el:\".app\",",
" data:{",
" message:\"hello.vue!\"",
" }",
" });",
" </script>",
"</body>",
"</html>",
]
}
}
4.3
二.VUE基本语法
记得要导入cdn哦。
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
2.1声明式渲染:vue给标签属性单向传值(只适合小范围的数据共享)
1、Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。
2、只有文本传值才要加{{}},v-bind,v-if属性中的传值不用加{{}},
2.1.1 渲染一个字符串:vue给文本单向传值
<!--{{xxx}}来绑定文本 -->
<div id="app">
{{message}}
</div>
<!-- 使用一个vue对象绑定一对标签-->
<script>
var vm=new Vue({
el:"#app",
data:{
message:"hello.vue!"//定义属性和默认初始值,不想要默认初始值就置为message: ''
}
});
</script>
2.1.2 绑定属性(v-bind:或:):vue给标签的属性单向传值
v-bind:index通常会简写为:index,这样是为了能够识别其中的变量和运算符。
Vue绑定数据v-bind缩写:字段名双向绑定v-model缩写:model 监听动作v-on缩写@
<div id="app">
<div v-bind:title="message"><!-- 这里是给div的title属性传值 -->
鼠标悬停此处查看状态
</div>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data:{
message:'页面加载与'+new Date().toLocaleString()
}
});
</script>
2.2 条件渲染(v-if,v-else)
==会将数据类型转化》,最后比较值;
===比较数据类型和值
<div id="app">
<h1 v-if="type==='a' ">a</h1>
<h1 v-else-if="type==='b' ">b</h1>
<h1 v-else>else</h1>
</div>
<script>
var app=new Vue(
{
el:"#app",
data:{
ok: true,
type: 'd'
}
}
)
</script>
2.3 列表渲染(v-for)
<div id="app">
<!-- 这遍历一个数组,类似于foreach循环-->
<li v-for="item in items">
{{ item.message}}
</li>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data:{
items:[{message:"aaaaaa"},{message: "bbbbbbb"}]
}
});
</script>
也可以多加一个值作为该循环时数组的下标。可以用{{index+1}}来使得下标加1
<div id="app">
<!-- 这遍历一个数组,类似于foreach循环-->
<li v-for="(item,index) in items">
{{ item.message}}-0{{index+1}}
</li>
</div>
<script>
new Vue({
el: '#app',
data:{
items:[{message:"aaaaaa"},{message: "bbbbbbb"}]
}
});
</script>
2.4 vue绑定事件 (v-on:):绑定触发事件
<div id="app">
<!-- 这遍历一个数组,类似于foreach循环-->
<button v-on:click="sayHi">click me</button>
</div>
<script>
new Vue({
el: '#app',
data:{
message: "你好呀!"
},
methods:{//方法一定要定义在Vue的Methods对象中
sayHi: function (event){
alert(this.message);
}
}
});
</script>
2.5 文本双向绑定(v-model)
用v-model 指令使得input的值和vue对象实现数据双向绑定的效果。
2.5.1 input和vue对象
<div id="app">
<!-- 当修改输入在input中时,vue中的message也会发生变化,修改message,vue中的值也会发生变化。-->
输入的文本1:<input type="text" v-model="message">
<hr>
输入的文本2:<input type="text" v-model="message">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data:{
message: "你好呀!"//定义属性和默认初始值,不想要默认初始值就置为message: ''
},
methods:{//方法一定要定义在Vue的Methods对象中
sayHi: function (event){
alert(this.message);
}
}
});
</script>
展示效果如下
2.5.2 绑定textarea标签(绑定innerText)
<div id="app">
<!-- 当修改输入在textarea中时,后面{{message}}所展示的值也会发生变化,即前面值保持同步且相等-->
输入的文本:<textarea name="" id="" cols="" rows="" v-model="message"></textarea> {{message}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data:{
message: "你好呀!"//定义属性和默认初始值,不想要默认初始值就置为message: ''
},
});
</script>
结果页面展示如下:
2.5.3 绑定select标签(绑定selected)
<div id="app">
<!-- 当修改输入在textarea中时,后面{{message}}所展示的值也会发生变化,即前面值保持同步且相等-->
<select name="" id="" v-model="hah">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
value:{{hah}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data:{
hah: 'C'
},
});
</script>
结果页面展示如下:
2.6 vue的组件:html的标签
2.6.1局部组件:作用域为本vue的指定标签
<div id="app">
<aaa></aaa> //3、组件的使用
</div>
<script>
//1、定义vue的作用标签(作用域)
var vm=new Vue({
el:'#app',
components:{//2、定义vue组件,aaa是组件名,template是组件的内容
'aaa':{
template:'<ul><li>java</li><li>python</li></ul>'
}
}
})
</script>
2.6.2全局组件:作用域为整个html文件
可以通过导入全局组件来达到整个工程都能使用该全局组件的效果。
<div id="app">
<!--4.使用hhh标签,这里还用上了for循环遍历vue的数组属性-->
<hhh v-for="item in items" v-bind:aaa="item"/>
</div>
<script>
//1.定义一个vue的主键component
Vue.component("hhh",{
props: ['aaa'],//2.通过props向template中传递数据
template: '<li>{{aaa}}</li>'
});
//3.定义vue的作用标签(作用域)
var vm=new Vue({
el:'#app',
data:{
items: ["java","linux","python"]
}
})
</script>
三、vue的生命周期
<div id="app">
hello
</div>
<script src="vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
},
created() {//在页面渲染之前会调用created()。
debugger
console.log('created....')
},
mounted() {//在页面渲染之后会调用mounted()。
debugger
//在页面渲染之后执行
console.log('mounted....')
}
})
</script>
3.1 created :在进行template渲染前会自动执行该函数。
3.2 mounted:在进行template渲染后会自动执行该函数。
四、vue路由:点击菜单栏显示不同的子页面(重点)
4.1 普通形式
1、前端路由实现前端局部组件更换。
自己下载vue-router.min.js;先引入vue.min.js,再引入vue-router.min.js
2、实现原理:router-link导航(即目录)—>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 1、router-link是vue 内置标签 -->
<!-- html中使用 router-link 组件来导航,通过属性`to`的值来指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a></a>` 标签的样式 -->
<router-link to="/">首页</router-link>
<router-link to="/student">会员管理</router-link>
<router-link to="/teacher">讲师管理</router-link>
</p>
<!-- 6、router-view也是vue 内置标签,是路由的出口 -->
<!-- 路由匹配到的组件将被渲染在这里 -->
<!-- 该标签必须在路由器的作用范围内 -->
<router-view></router-view>
</div>
<script src="vue.min.js"></script>
<script src="vue-router.min.js"></script>
<script>
// 2. 定义路由映射关系的数组,以下固定格式才能被vue服务器通过内部接口成功读取数据
const xxx = [
{ path: '/', redirect: '/welcome' }, //设置默认指向的路径
{ path: '/welcome', component: Welcome },
{ path: '/student', component: Student },
{ path: '/teacher', component: Teacher }
]
// 3. 定义路由跳转到的组件的内容,也可以从其他文件 import 进来组件
//template:'<div>欢迎</div>'就相当于4.3中的<template><div>欢迎</div></template>效果
const Welcome = { template: '<div>欢迎</div>' }
const Student = { template: '<div>student list</div>' }
const Teacher = { template: '<div>teacher list</div>' }
// 4. 通过路由映射关系创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
xxx // (缩写)相当于 routes: routes
})
//5、创建vue对象。确定路由的作用域。
const app = new Vue({
el: '#app',
router
})
</script>
4.2 简写形式
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 1、router-link是vue 内置标签 -->
<!-- html中使用 router-link 组件来导航,通过属性`to`的值来指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a></a>` 标签的样式 -->
<router-link to="/">首页</router-link>
<router-link to="/student">会员管理</router-link>
<router-link to="/teacher">讲师管理</router-link>
</p>
<!-- 4、router-view也是vue 内置标签,是路由的出口 -->
<!-- 路由匹配到的组件将被渲染在这里 -->
<!-- 该标签必须在路由器的作用范围内 -->
<router-view></router-view>
</div>
<script src="vue.min.js"></script>
<script src="vue-router.min.js"></script>
<script>
// 2、 通过路由映射关系的数组来创建路由器实例,这是个非常简单的实例,在项目中每个对象通常都非常复杂。
const router = new VueRouter({
// routes // (缩写)相当于 routes: routes
routes:[
{ path: '/', redirect: '/welcome' }, //配置默认指向的路径为第一个界面(/welcome)
{ path: '/welcome', component: { template: '<div>欢迎</div>'} },
{ path: '/student', component: { template: '<div>student list</div>' } },
{ path: '/teacher', component: { template: '<div>teacher list</div>' } }
]
})
//3、创建vue对象。确定路由的作用域。
new Vue({
el: '#app',
router
})
//或者使用以下简写
// new Vue({
// router
// }).$mount('#app')
</script>
4.3项目中常用element-ui+vue
(1) router-link部分(很难找,大概在components里面)
路由的router-link标签通常不用了,而是用element-ui的的模板。即每当我们往Router中添加一个对象的时候,就会在菜单栏上体现
<template>
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:show-timeout="200"
:default-active="$route.path"
:collapse="isCollapse"
mode="vertical"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
>
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path"/>
</el-menu>
</el-scrollbar>
</template>
<script>
import { mapGetters } from 'vuex'
import SidebarItem from './SidebarItem'
export default {
components: { SidebarItem },
computed: {
...mapGetters([
'sidebar'
]),
routes() {
return this.$router.options.routes
},
isCollapse() {
return !this.sidebar.opened
}
}
}
</script>
(2) 路由映射关系来创建路由映射实例
import Vue from 'vue'
import Router from 'vue-router'
//1.Vue Router是Vue.js 官方的路由管理器。 它和Vue.js的核心深度集成,可以非常方便的用于SPA应用程序的开发。
//以下通过new Router创建路由器就是Vue.use(Router)的效果
Vue.use(Router)
//2、导入路由的布局样式,在views/layout/Layout下就有路由界面的布局风格的代码
import Layout from '../views/layout/Layout'
//3、这里用一个任意的对象数组,其中有效的属性才会被new Router读取成功
export const constantRouterMap = [
{
path: '/teacher',
component: Layout,//路由的布局样式(如侧边拦,颜色,宽度等等)
redirect: '/teacher/table',//默认重定向到table
name: '讲师管理',//显示在侧边拦
meta: { title: '讲师管理', icon: 'example' },//icron是图标,地址是src/icons/svg/example.svg
children: [
{
path: 'table',
name: '讲师列表',
//1、@代表src下,表示点击会跳转到src/views/edu/teacher/list
//2、src/views/edu/teacher/list下会有具体的<template>...</template>组件
component: () => import('@/views/edu/teacher/list'),
meta: { title: '讲师列表', icon: 'table' }
},
{
path: 'save',
name: '添加讲师',
component: () => import('@/views/edu/teacher/save'),
meta: { title: '添加讲师', icon: 'tree' }
}
]
},
{...},
...
]
//4、Router是import Router from 'vue-router'得到的。里面routes: constantRouterMap内的对象属性在vue-router中有语义规范(就是说只有import Router能够被读取数组的对象的属性中的有效值)
export default new Router({
// mode: 'history', //后端支持可开
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
(3) 路由器的作用域在src/main.js中
import Vue from 'vue'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import '@/styles/index.scss' // global css
import App from './App'
import router from './router'
import store from './store'
import '@/icons' // icon
import '@/permission' // permission control
Vue.use(ElementUI, { locale })
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
(4)router-view在src/APP.vue中
-----------路由的组件
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
【原理】路由器的本质理解
1、我们能看到路由器的本质就是把程序中多个组件全部都导入到一个一个Vue对象中(即main.js中的new Vue({})),然后根据url将App.vue中标签渲染成我们想要的组件内容。一个vue项目的本质就是main.js中的一个Vue实例,路由的本质上起着components的效果,只是将所有被渲染的标签统一为< router-views/>
2、一个项目的本质就是一个Vue实例对象,里面通过路由导入了多个组件。本项目中所有的this都是指代本组件的内容,即export default{}这个作用域对象,不可通过this.调用其他对象的内容。
var vm=new Vue({
el:'#app',
components:{
'aaa':{
template:'<ul><li>java</li><li>python</li></ul>'
}
'bbb':{
template:'<ul><li>java</li><li>python</li></ul>'
}
}
})
五.vue的网络通信Axios(超级重点、难点)
5.1使用Axios来给服务器发送请求
我们用Axios来给服务器发送get请求,使用json模拟服务器返回的数据
----------data.json
{
"success":true,
"code":2000,
"message":"成功",
"data":{
"items":[
{"name":"lucy","age":20},
{"name":"mary","age":30},
{"name":"jack","age":40}
]
}
}
----------html
<script src="vue.min.js"></script>
<script src="axios.min.js"></script>
<script>
new Vue({
el: '#app',
//固定的结构
data: { //在data定义变量和初始值
//定义变量,值空数组
userList:[]
},
created() { //页面渲染之前执行
//调用methods中定义的方法
this.getUserList()
},
methods:{
//定义方法来查询所有用户数据
getUserList() {
//使用axios发送ajax请求:
//axios.提交方式("请求接口路径").then(箭头函数).catch(箭头函数)
//1.请求方式:get,post,delete
//2.接口路径如:http://localhost:8081/admin/ucenter/member
//3.给后端发出请求后若成功返回响应则执行then方法,请求失败则返回catch方法
axios.get("data.json")
.then(response =>{
//response就是请求之后返回数据的形参名,我们当然可以不使用response而使用aaa
console.log(response)
//通过response获取具体数据,赋值给定义空数组
//this.userList = response.data.data.items
//console.log(this.userList)
})
.catch(error =>{//error就是请求之后返回数据的形参名
})
}
}
})
</script>
【注意】
1.安装Live Server插件
2.右键选择 Open with Live Server
3.进入浏览器控制台后,刷新浏览器就能显示出一下效果
5.2 Promise详解(重要)
Promise 是一个对象,它代表了一个异步操作的最终完成或者失败,如成功时回调函数1,失败时回调函数2。而我们通常会vue程序中用Promise来对axios.request产生的结果进行回调。
1、箭头函数的箭头看作return就好理解了,这里return {},
2、Promise的构造方法传入两个参数,通常用(resolve, reject),这里用(a,b)是为了说明这两个形参名是不固定。
- 当操作成功时,Promise的状态将置为fullfiled,构造方法的第一个参数将会被作为p.then()函数的传入参数
- 当操作失败时,Promise的状态置为rejected,构造方法的第二个参数将会被作为p.catch()函数的传入参数
3、我们通常会使用链式编程:即new Promise((a,b)=>{}).then((s)=>{}).catch((e)=>{});
//1、箭头函数的箭头看作return就好理解了,这里return {},
//2、Promise的构造方法传入两个参数,通常用(resolve, reject),这里用(a,b)是为了什么形参名不固定
//构造方法的第一个参数将会被作为p.then()函数的传入参数,
//构造方法的第二个参数将会被作为p.catch()函数的传入参数。
//3、我们通常会使用链式编程:即new Promise((a,b)=>{}).then((s)=>{}).catch((e)=>{});
let p = new Promise((a,b) => {
a("成功传出去的对象");
b("失败传出去的对象");
});
p.then(
(s) => {
console.log("s:"+s);//输出 s:成功传出去的对象
}
);
p.catch((e) => {
console.log("e:"+e);//当异常时就会输出 e:失败传出去的对象
})
5.3 项目中使用axios.request()通信(非常重要)
其核心一套操作在项目中通常会被分开写,如果连续写则 如下所示:
new Promise((resolve, reject) => {axios.create({baseURL:’’}).request({url:’’,…}).then(response =>{}).catch(error =>{})}).then((resolve)=>{}).catch((reject)=>{})
其中resolve(response),reject(error)都是Promise内的静态方法。
// 1、在util上目录下:创建axios的基本信息
const xxx = create({//1、axios.create的略写 2、创建出来一个axiosInstance,这样才行使用baseURL
baseURL: "http://localhost:8001", // api 的 base_url
timeout: 5000 // 请求超时时间
})
--------------------------------分页:第二页----------------------------------------
import aaa from 'axios'
// 2、api目录:
//调用login函数就相当于调用以下request函数。当我们直接调用login(username, password)时就相当于service.request({...}),这里是进行了一些封装。
export function login(username, password) {
//1、其实是xxx.request()的略写,而不是axios.request的略写
//2、xxx(axios的实例对象)里面有request,get,post,delete,patch等静态方法
//3、get请求的传参params:{},post请求的传参是data:{}
return request({
url: '/hello',
method: 'get',
params: { username }+":xxx"
})
}
--------------------------分页:第三页----------------------------------------------------------------
// 3、在store目录下会调用api下的login函数,即给对应的url发送请求并得到响应
const user = {
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
login(username, userInfo.password).then(response => {//调用的是api/login.js中的login函数,login里面本质上就是server.request函数
const data = response.data
setToken(data.token)
commit('SET_TOKEN', data.token)
resolve()
}).catch(error => {
reject(error)
})
});//return语句结束
},
}
}
【问题解决】跨域问题
当我们通过一个url地址去访问另一个url地址,如果两者有以下任何一个地方不一样就会发生跨域问题。也就是说,跨域问题是不可避免的。如:
访问协议 http https
ip地址 192.168.1.2 172.33.1.1
端口号 953 80
方法一、使用@CrossOrgin注解解决跨域问题
方法一:在后端controller类上添加注解@CrossOrgin
方法二、使用网关解决跨域问题
六、vuex的使用
vue中使用v-bind和v-on只适合小范围的数据共享,而大范围的数据共享则需要用到vuex。vuex是实现组件全局状态管理的一种机制,方便组件之间的数据共享。一般在vuex中存储共享的数据,在vue的data中存储自己的数据。
6.1 使用vue ui来创建vue项目
(1) 安装并打开vue界面
1、npm install -g @vue/cli控制台安装Vue CLI
2、通过vue ui打开vue界面【注意】
如果vue ui没有反应那可能是vue版本太低,要高于版本3才行
重装vue-cli的指令如下:
1、卸载:npm uninstall vue-cli -g
2、重装:npm install @vue/cli -g
(2) 选择路径创建vue项目并进行vue项目的配置
1、
2、
3、
4、添加依赖
5、
6、不存储预设直接开始就行
(3) 打开项目
(4)关闭vue的eslint语法检查
-----------------------------在根目录下创建vue.config.js
module.exports = {
lintOnSave: false,
devServer: {
overlay: {
warnings: true,
errors: true
}
}
}
6.2 vue2生成的初始源码分析
(1)唯一核心文件:main.js
1、在 Vue3 中,新建 Vue 实例是通过 createApp 函数,而不是通过 new Vue。
2、new Vue().KaTeX parse error: Expected 'EOF', got '#' at position 8: mount('#̲app')的作用是vue实例挂…mount(’#app’)和是固定写法(不能改,如果更改$mount(’#xxx’)就会白屏)
3、import xxx from ‘./xxx’ 是import xxx from './xxx.vue’的简写,xxx就是我们写好的xxx.vue界面。
import Vue from 'vue'
//1、是import xxx from './xxx.vue'的简写,xxx就是我们写好的xxx.vue界面。
//2、为了区分,我是用import x from './xxx',然后render: h => h(x),最后也能一样实现挂载。
import x from './xxx'
import store from './store'
Vue.config.productionTip = false
new Vue({
// store,//为了避嫌,把它给先注释了。
//1、render是渲染的意思,可以通过修改xxx来更改我们所使用的.vue文件
//2、使用 Render 函数将 Template 里面的节点解析成虚拟的 Dom。简单的说,在 Vue 中我们使用模板 HTML 语法组建页面的,使用 Render 函数我们可以用 Js 语言来构建 DOM。因为 Vue 是虚拟 DOM,所以在拿到 Template 模板时也要转译成 VNode 的函数,而用 Render 函数构建 DOM,Vue 就免去了转译的过程。
render: h => h(x)
}).$mount('#app')
//1、new Vue().$mount('#app')的作用是vue实例挂载到#app的元素上,但是官方解释template将会替换挂载的class="app"元素(挂载id="app"元素的内容都将被省略不写)。
//所以在vue2中.$mount('#app')和<template></template>是固定写法(不能改,如果更改$mount('#xxx')就会白屏)
//2、这语法实际上就是vue 1.x下的(使用App组件下的#app元素):
// new Vue({
// el: '#app',
// components: { App }
// });
//3、语法解释:
//1、render函数的官方定义如下
// render: function (createElement) {
// return createElement(
// 'h' + this.level, // tag name 标签名称,this是
// this.$slots.default // 子组件中的阵列,其中$只是一个特殊标记。用来区分的,来说明这是内置的实例方法属性。
// )
// }
// 2、h => h(App)就是一个箭头函数,我们完全可以改成 x => x(App) ,一样生效。如下:
// (function (h) { //其中h(指Hyperscript)vue作者对createElement的简写。
// return h(App);
// });
(2)被挂载的元素文件xxx.vue
-------------xxx.vue(默认是App.vue,我这里是为了说明这个文件名不固定就特意用了xxx.vue来距离)
<template>
<div id="b"><!--原代码是id="app",我改成b是为了区分这个div标签和main.js中的.$mount('#app')没有关系,.$mount('#app')是挂载在template上的 -->
hello12341234
<div id="c">
hello12341234
afds
</div>
safsdfasfdsaf
</div>
</template>
<style>
#b {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #ff0000;
margin-top: 60px;
}
#c {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #52ff02;
margin-top: 60px;
}
</style>
6.3Vuex的核心概念
以下的state,mutation,action都有两中触发方式,但是在index.js中的定义方式就只有一种哦。
--------------------主面板:xxx.vue(这是被main.js所使用的vue)
<template>
<div>
<myAdd></myAdd>
<p>---------------------------</p>
<mySub></mySub>
</div>
</template>
<script>
import A from '../src/components/Addition'
import S from '../src/components/Subtraction'
export default {
data(){
return {};
},
components:{//导入两个组件,并把它们注册为xxx的子组件
'myAdd':A,
'mySub':S
}
}
</script>
-----------------store.index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//将vuex安装到项目中:
//1、调用vuex的install方法,判断Vuex是否已经注册过了,注册过了就直接返回,这里使用的是单例模式。
//2、调用applyMixin(Vue)
//3、将初始化vuex的方法(vuexInit)混入到vue的beforeCreate生命周期中;
//4、将$store绑定到每个vue实例中。
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
6.3.1关于state
(1)定义state中的数据state
-----------------store.index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//将vuex安装到项目中:
//1、调用vuex的install方法,判断Vuex是否已经注册过了,注册过了就直接返回,这里使用的是单例模式。
//2、调用applyMixin(Vue)
//3、将初始化vuex的方法(vuexInit)混入到vue的beforeCreate生命周期中;
//4、将$store绑定到每个vue实例中。
export default new Vuex.Store({
//1、提供唯一公共数据源,本项目的所有的公共数据都要统一发到Store的state中
//2、项目中访问数据的两种方法:
//第一种方式:this.$store.state.count
//第二种方式: 使用import {mapState} from 'vuex',然后通过...mapState(['count'])得到数据并存放在组件的computed属性中。
state: {
count: 0
},
mutations: {
},
actions: {
},
modules: {
}
})
(2)访问state中的数据的第一种方法:直接使用全局变量
-----------------------Addition.vue(模板类中)
<template>
<div>
<!-- 原本是this.$store.state.count,但是在template中this可以省略 -->
<h3>当前最新的count值为:{{$store.state.count}}</h3>
<button>+1</button>
</div>
</template>
<script>
export default {
date(){
return {};
}
}
</script>
(3)访问state中数据的第二种方法:映射全局变量
--------------Subtraction.vue(模板类中)
<template>
<div>
<h3>当前最新的count值为:{{count}}</h3>
<button>-1</button>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
date(){
return {};
},
computed: {
...mapState(['count'])//...是展开运算符。是指将某个全局数据(count)映射为当前组件的属性
}
}
</script>
6.3.2 使用mutation来修改state中的数据
(1)定义mutation(有参无参)
-----------------store.index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//将vuex安装到项目中:
//1、调用vuex的install方法,判断Vuex是否已经注册过了,注册过了就直接返回,这里使用的是单例模式。
//2、调用applyMixin(Vue)
//3、将初始化vuex的方法(vuexInit)混入到vue的beforeCreate生命周期中;
//4、将$store绑定到每个vue实例中。
export default new Vuex.Store({
//1、提供唯一公共数据源,本项目的所有的公共数据都要统一发到Store的state中
//2、在项目中的访问方式第一种方式:this.$store.state.count
//第二种方式: 使用import {mapState} from 'vuex',然后通过...mapState(['count'])得到数据并存放在组件的computed属性中。
state: {
count: 0
},
mutations: {//定义addN函数和subN函数
add(state){
state.count+=1
},
addN(state,step1){//有参
state.count+=step1
},
sub(state){
state.count-=1
},
subN(state,step){//有参
state.count-=step
}
},
actions: {
},
modules: {
}
})
(2)触发mutation的第一种方式
a.无参调用mutation内函数
直接使用this.$store.commit(‘add’)来调用
------------------Addition.vue
<template>
<div>
<h3>当前最新的count值为:{{$store.state.count}}</h3> <!-- 原本是this.$store.state.count在template中this可以省略 -->
<button @click="btnHandler01">+1</button>
</div>
</template>
<script>
export default {
date() {
return {};
},
methods: {
btnHandler01() {
this.$store.commit('add');//通过commit函数能够调用mutations中的函数
}
}
}
</script>
b.传参参调用mutation内函数
直接使用this.$store.commit(‘addN’,3);来调用
------------------Addition.vue
<template>
<div>
<h3>当前最新的count值为:{{$store.state.count}}</h3> <!-- 原本是this.$store.state.count在template中this可以省略 -->
<button @click="btnHandler01">+1</button>
<button @click="btnHandler02">+N</button>
</div>
</template>
<script>
export default {
date() {
return {};
},
methods: {
btnHandler01() {
this.$store.commit('add');//通过commit函数能够调用mutations中的函数
},
btnHandler02() {
this.$store.commit('addN',3);//通过commit函数能够调用mutations中的函数
}
}
}
</script>
(3)触发mutation的第二种方式
1、展开运算符导入
2、调用this.sub()可以触发mutation中的sub函数。
------------------Subtraction.vue
<template>
<div>
<h3>当前最新的count值为:{{count}}</h3>
<button @click="btnHandler01">-1</button>
<button @click="btnHandler02">-N</button>
</div>
</template>
<script>
import {mapState,mapMutations} from 'vuex'
export default {
date(){
return {};
},
computed: {
...mapState(['count'])//...是展开运算符。mapState是把全局变量映射到当前组件的一个属性
},
methods:{
...mapMutations(['sub','subN']),//...是展开运算符。mapMutations是把全局函数映射到当前组件的函数
btnHandler01(){
this.sub()
},
btnHandler02(){
this.subN("3")
}
}
}
</script>
【注意】直接使用this.$store.state.count或…mapState([‘count’])来修改全局数据是不被推荐的,而是推荐使用mutation来修改state中的数据。
<template>
<div>
<h3>当前最新的count值为:{{$store.state.count}}</h3> <!-- 原本是this.$store.state.count在template中this可以省略 -->
<button @click="btnHandler01">+1</button>
</div>
</template>
<script>
export default {
date() {
return {};
},
methods: {
btnHandler01() {
this.$store.state.count++;//不推荐使用
}
}
}
</script>
6.3.3 action()
(1)定义action的方式(有参无参)
-----------------store.index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//1、提供唯一公共数据源,本项目的所有的公共数据都要统一发到Store的state中
//2、在项目中的访问方式第一种方式:this.$store.state.count
//第二种方式: 使用import {mapState} from 'vuex',然后通过...mapState(['count'])得到数据并存放在组件的computed属性中。
state: {
count: 0
},
//只有mutations中定义的函数才有权利修改state中的数据
mutations: {
add(state){//有参
state.count+=1
},
addN(state,step1){//有参
state.count+=step1
},
sub(state){//定义subN函数
state.count-=1
},
subN(state,step){
state.count-=step
}
},
//在actions中不能直接修改state中的数据,而是通过context.commit()来触发mutation来修改state中的数据
actions: {
addAsync(context){//使用this.$store.dispatch('addAsync')来触发actions函数
setTimeout(()=>{
context.commit('add')
},1000)
},
addNAsync(context,step){//传参
setTimeout(()=>{
context.commit('addN',step)
},1000)
},
subAsync(context){//传参
setTimeout(()=>{
context.commit('sub')
},1000)
},
subNAsync(context,step){//传参
setTimeout(()=>{
context.commit('subN',step)
},1000)
}
},
modules: {
}
})
(2)触发action的第一种方式
直接调用全局变量:this.$store.dispatch(‘addAsync’)。
------------------Addition.vue
<template>
<div>
<h3>当前最新的count值为:{{$store.state.count}}</h3> <!-- 原本是this.$store.state.count在template中this可以省略 -->
<button @click="btnHandler01">+1</button>
<button @click="btnHandler02">+N</button>
<button @click="btnHandler03">+1 Async</button>
<button @click="btnHandler04">+N Async</button>
</div>
</template>
<script>
export default {
date() {
return {};
},
methods: {
btnHandler01() {
this.$store.commit('add');//通过commit函数能够调用mutations中的函数
},
btnHandler02() {
this.$store.commit('addN',3);//通过commit函数能够调用mutations中的函数
},
btnHandler03() {//异步让count自增+1
this.$store.dispatch('addAsync');//通过this.$store.dispatch来触发action中的函数
},
btnHandler04() {//异步传参
this.$store.dispatch('addNAsync',4);//通过this.$store.dispatch来触发action中的函数
}
}
}
</script>
(3)触发action的第二种方式
1、导入:…mapActions([‘subAsync’,‘subNAsync’])
2、直接调用this.subAsync()
------------------Subtraction.vue
<template>
<div>
<h3>当前最新的count值为:{{count}}</h3>
<button @click="btnHandler01">-1</button>
<button @click="btnHandler02">-N</button>
<button @click="btnHandler03">-1 Async</button>
<button @click="btnHandler04">-N Async</button>
</div>
</template>
<script>
import {mapState,mapMutations,mapActions} from 'vuex'
export default {
date(){
return {};
},
computed: {
...mapState(['count'])//...是展开运算符。mapState是把全局变量映射到当前组件的一个属性
},
methods:{
...mapMutations(['sub','subN',]),//...是展开运算符。mapMutations是把全局函数映射成当前组件的函数
...mapActions(['subAsync','subNAsync']),//...是展开运算符。把全局actions中方法映射成当前组件中的方法
btnHandler01(){
this.sub()
},
btnHandler02(){
this.subN(3)
},
btnHandler03(){
this.subAsync()
},
btnHandler04(){
this.subNAsync(3)
}
}
}
</script>
【注意】关于异步的理解(重要)
javascript的执行环境为单线程,所以程序在执行的时候只能按照顺序执行,而其中一个程序要占用大量的时间,会导致后面的程序过长的等待,造成阻塞的情况。当某些操作
需要花费大量时间但是并不怎么消耗资源
时,设计者就考虑把这些空出来的资源给其他操作使用,这就是异步操作的由来。javascrpt中的异步操作不同于多线程执行,当执行需要消耗大量资源的操作时,异步是可能会阻塞,而多线程就不会。常见的异步操作有:定时器、ajax、事件绑定、回调函数、async await、promise等,这些操作都是要需要花费大量时间等待但是并不怎么消耗资源的操作。
【注意】我们最好不要在mutation中使用像延时这类的异步操作,而是在Action中处理异步任务。如我们想要设置延时器的功能。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {//定义addN函数和subN函数
add(state){
setTimeout(()=>{//在mutations中设置计时器
state.count++
},1000)
},
addN(state,step1){//有参
state.count+=step1
},
sub(state){
state.count-=1
},
subN(state,step){//有参
state.count-=step
}
},
actions: {
},
modules: {
}
})
6.3.4 Getter:用于对store中的数据进行加工从而形成新的数据。
Getter不修改store中的原数据,而是对数据进行包装作用。当store中的数据进行变换之后,Getter中的数据也会发生变化。
我们可以把Getter当做state中数据的get方法,mutation当做state中数据的set方法,把actions用来定义程序需要调用的函数。
(1)定义getters
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//1、提供唯一公共数据源,本项目的所有的公共数据都要统一发到Store的state中
//2、在项目中的访问方式第一种方式:this.$store.state.count
//第二种方式: 使用import {mapState} from 'vuex',然后通过...mapState(['count'])得到数据并存放在组件的computed属性中。
state: {
count: 0
},
//只有mutations中定义的函数才有权利修改state中的数据
mutations: {
add(state){//有参
state.count+=1
},
addN(state,step1){//有参
state.count+=step1
},
sub(state){//定义subN函数
state.count-=1
},
subN(state,step){
state.count-=step
}
},
//在actions中不能直接修改state中的数据,而是通过context.commit()来触发mutation来修改state中的数据
actions: {
addAsync(context){//使用this.$store.dispatch('addAsync')来触发actions函数
setTimeout(()=>{
context.commit('add')
},1000)
},
addNAsync(context,step){//传参
setTimeout(()=>{
context.commit('addN',step)
},1000)
},
subAsync(context,step){//传参
setTimeout(()=>{
context.commit('sub',step)
},1000)
},
subNAsync(context,step){//传参
setTimeout(()=>{
context.commit('subN',step)
},1000)
}
},
getters:{
showNum(state){//可以通过this.$store.getters.showNum来获取return的值。
return '当前最新的数量是【'+state.count+'】'
}
},
modules: {
}
})
(2)触发action的第一种方式
使用 {{$store.getters.showNum}}
<template>
<div>
<h3>{{$store.getters.showNum}}</h3> <!-- 原本是this.$store.state.count在template中this可以省略 -->
<button @click="btnHandler01">+1</button>
<button @click="btnHandler02">+N</button>
<button @click="btnHandler03">+1 Async</button>
<button @click="btnHandler04">+N Async</button>
</div>
</template>
<script>
export default {
date() {
return {};
},
methods: {
btnHandler01() {
this.$store.commit('add');//通过commit函数能够调用mutations中的函数
},
btnHandler02() {
this.$store.commit('addN',3);//通过commit函数能够调用mutations中的函数,注意是加3而不是加'3'
},
btnHandler03() {//异步让count自增+1
this.$store.dispatch('addAsync');//通过this.$store.dispatch来触发action中的函数
},
btnHandler04() {//异步传参
this.$store.dispatch('addNAsync',4);//通过this.$store.dispatch来触发action中的函数
}
}
}
</script>
(3)触发action的第二种方式
1、在computed中使用展开运算符导入,
2、直接通过{{showNum}}来传值
<template>
<div>
<h3>{{showNum}}</h3>
<button @click="btnHandler01">-1</button>
<button @click="btnHandler02">-N</button>
<button @click="btnHandler03">-1 Async</button>
<button @click="btnHandler04">-N Async</button>
</div>
</template>
<script>
import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'
export default {
date(){
return {};
},
computed: {
...mapState(['count']),//...是展开运算符。mapState是把全局变量映射到当前组件的一个属性
...mapGetters(['showNum'])
},
methods:{
...mapMutations(['sub','subN',]),//...是展开运算符。mapMutations是把全局函数映射成当前组件的函数
...mapActions(['subAsync','subNAsync']),//...是展开运算符。把全局actions中方法映射成当前组件中的方法
btnHandler01(){
this.sub()
},
btnHandler02(){
this.subN(3)
},
btnHandler03(){
this.subAsync()
},
btnHandler04(){
this.subNAsync(3)
}
}
}
</script>
七、element-ui:快速页面布局
element-ui中文版
element-ui是基于vue.js的后台组件库,能够快速页面布局
八、node.js:javascript的运行环境
正如jdk是java的运行环境,node.js也是javascript的运行环境,有了node.js,我们就不需要浏览器来运行javascript了。实际上,node.js正是使用了google的javascript引擎(v8).
正如我们需要安装jdk一样,我们也需要在电脑上安装node.js
8.1下载并安装node.js
官网下载node.js
如果node -v能得到版本,则说明安装成功。
8.2使用node.js运行javascript代码
node test.js
8.3服务器端的应用开发(了解)
const http = require('http');
http.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应数据 "Hello World"
response.end('Hello Server');
}).listen(8888);
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
8.4VScode的集成终端来使用node.js
九、npm:node.js的包管理工具
在我们安装node.js时,npm会默认一起安装好了,因此不需要我们手动安装。
9.1项目初始化:生成package.json
当我们在某个文件夹下使用 npm init指令后,会发现在本文件中出现了一个package.json文件,这就类似于后端的pom.xml文件。
npm init或npm init -y
9.2配置镜像
1.npm config set registry https://registry.npm.taobao.org
2.npm config list
9.3下载某个依赖
npm install jquery下载最新版本
npm install jquery@2.1.x下载指定版本
下载后能得到如下的一个文件夹
9.4根据package.json内容批量下载依赖
npm install
十、babel转码器:把es6代码转换成es5
es5兼容性更好。
10.1使用VScode下载babel
(1) 先初始化
babel init
(2) 再下载babel-cli
npm install --global babel-cli
(3) 设置权限并查看版本
get-ExecutionPolicy
set-ExecutionPolicy RemoteSigned
babel --version
10.2在项目中使用babel
(1) 在es6中写一段es6代码,并在babeldemo的根目录下配置一个.babelrc
文件
---------01.js
let input = [1,2,3]
input = input.map(item=>item + 1)
console.log(input)
-------------- .babelrc
{
"presets": ["es2015"],
"plugins": []
}
(2) 下载并安装es2015的转码器
npm install --save-dev babel-preset-es2015
如果下载失败或下载了很久,就ctrl+c关闭,然后重新下载。
(3) 使用命令进行转码
将某个文件转码
babel es6/01.js -o dist/001.js
将整个文件夹内容都转码
babel es6/01.js -o dist/001.js
babel es6 -d dist
十一、模块化:实现js文件与js文件之间之间方法的调用
11.1 es5的模块化
以下实现02.js调用01.js中的加法函数却没有调用成功减法函数
---------01.js
//1、创建js方法
// 加法函数
const sum=function(a,b){
return parseInt(a)+parseInt(b)
}
// 减法函数
const subtract=function(a,b){
return parseInt(a)-parseInt(b)
}
//2、设置加法能够被其他js文件调用,减法不能
module.exports={
sum
}
---------02.js
//1、引入01.js文件
const m = require("./01.js")
//2、调用方法
console.log(m.sum(1,3))
console.log(m.subtract(3,1))
11.2 es6的模块化
(1) 先写好代码
需要转换成es5,再进行模块化
---------01.js
//定义方法,加上export 就可以被其他js文件调用
export function getList(){
console.log("getList.....")
}
export function save(){
console.log("save.......")
}
---------02.js
//引入可以调用的方法
import {getList,save} from "./01.js"
//调用方法
getList()
save()
第二个常用格式
---------01.js
//定义可以被其他js文件调用
export default{
getList(){
console.log("getList.....")
},
save(){
console.log("save.......")
}
}
---------02.js
//引入可以调用的方法
import m1 from "./01.js"
//调用方式
m1.getList()
m1.save()
(2) 配置.babelrc
-------- .babelrc
{
"presets": ["es2015"],
"plugins": []
}
(3)下载并安装es2015的转码器
npm install --save-dev babel-preset-es2015
(4)使用指令进行转码
babel es6module -d es6module2
(5)查看转换成es5的文件内容
被转换的文件内容如下,我们发现完全符合es5的语法
------01.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getList = getList;
exports.save = save;
//定义方法,加上export 就可以被其他js文件调用
function getList() {
console.log("getList.....");
}
function save() {
console.log("save.......");
}
-------02.js
"use strict";
var _ = require("./01.js");
//调用方法
(0, _.getList)(); //引入可以调用的方法
(0, _.save)();
十二、webpack
Webpack是一个前端资源加载、打包工具,他能将多种css,js,less等静态资源文件打包成一个静态文件,减少了多文件页面调用请求而浪费资源。
12.1安装webpack工具:全局安装
(1) 在文件夹下初始化
npm init 生成package.json文件
(2) 安装webpack工具
npm install -g webpack webpack-cli
webpack --version:查看是否安装
11.2 打包js文件
(1) 创建3个js文件
-----------common.js
//exports说明可导出
exports.add=function(a,b){
return a + b;
}
-----------utils.js
//exports说明可导出
exports.info=function(str){
console.log()
document.write(str);//浏览器中输出
}
-----------main.js
const common=require("./common")
const utils=require("./utils")
common.info('hello common'+utils.add(1,2))
(2) 创建webpack的配置文件:webpack.config.js
配置文件名固定
---------webpack.config.js
const path=require("path");//Node.js内置模块
module.exports={
entry:'./src/main.js',//配置文件入口
output:{
path:path.resolve(_dirname,'./dist'),//输出文件夹路径,需要自己创建
filename:'bundle.js'//输出的一个文件名
}
}
---------webpack4以上用一下命令
const path = require('path')
module.exports = {
entry: path.join(__dirname, 'src/main.js'),
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
}
}
(3) 使用命令打包
执行webpack命令
------------得到的bundle.js文件内是如下一行代码
(()=>{var o={648:(o,n)=>{n.info=function(o){console.log(),document.write(o)}},555:(o,n)=>{n.add=function(o,n){return o+n}}},n={};function r(t){var e=n[t];if(void 0!==e)return e.exports;var i=n[t]={exports:{}};return o[t](i,i.exports,r),i.exports}(()=>{const o=r(648),n=r(555);o.info("hello common"+n.add(1,2))})()})();
(4) 测试:在一个html文件中导入js依赖,就能实现js、css等静态资源文件的全部效果
--------a.html
<script src="dist/bundle.js"></script>
>
![]()
11.3【打包CSS】
(1) 将CSS和js引入main.js文件中
const common=require("./common")
const utils=require("./utils")
require("./style.css")
common.info('hello common'+utils.add(1,2))
(2) 安装style.loader和css.loader
npm install --save-dev style-loader css-loader
(3) 修改webpack配置文件
const path = require('path')
module.exports = {
entry: path.join(__dirname, 'src/main.js'),
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
}
}
(4) 使用进行打包
webpack:输出文件会将覆盖存在的一个同名文件
(5) 在html中测试
<script src="dist/bundle.js"></script>
>
![]()