插件安装
前端代码太多缩进,建议这里设置成2个空格。
跨平台方案(一次代码,多平台使用):
Vue->Weex->uniapp
jq利用DOM操作,降低了ajax请求函数的复用性(js与html耦合性太高)。
而vue通过框架提供的指令实现数据双向绑定,我们只需要关注业务逻辑,而不需要直接操作DOM元素。
MVVM是前端视图层的分层,(仅相当于MVC中的V);
将视图层分为:Model,View,ViewModel
如果将MVC和MVVM结合,如下图(MVC中的M和V与MVVM中的MV不是一个东西)
model 是数据, data
view 是模板
vm 是 vm = new Vue();
vm 用了连接数据和视图, 视图的输入框绑定了v-model, 用户输入后会改变data;
model改变也会同步视图更新相关的依赖, 双向绑定就是vm起了作用
Vue与后端模板引擎的区别就在于:
后端模板引擎从后端控制器的Model中获取数据,然后通过形如th:text="${}"的指令将数据渲染到html中。
Vue从JavaScript中获取数据,然后通过形如v-text="msg"的指令将数据绑定到html中。
{{}}只替换占位符,v-text会替换标签中的内容。{{}}中可以写js代码
v-html的v-text的区别就在于v-html会解析html代码;
如果网速比较慢,{{}}替换之前会一闪而过。解决办法如下
<style>
[v-clock]{
display:none;
}
style>
设置title属性的标签,鼠标放上去后会浮出title。
v-bind用于与js中的vue实例中的data中的数据进行绑定(绑定的对象不能是普通字符串),可以缩写为冒号:
v-bind可以绑定为任意原有html属性值,如src、style等等
<a :href="url">a>
<a :class="flag?'red':'blue'">a>
也用于使行内可以使用js代码(参考vue中的css)
v-on用于与与js中的vue实例中的methods中的方法进行绑定,可以缩写为@
<body>
<div>
<h1>{{msg}}h1>
<input type="text" v-model="msg">
div>
body>
<script>
var vue = new Vue({
el:'#app',//绑定目标
data:{
msg:'我是msg'
}
})
script>
当我们在input中输入数据的时候,h1内的数据也会改变。
最重要的是,其实vue实例中的msg也被修改了
v-model实现了表单元素和model中数据的双向绑定
但是v-model只能用于表单元素,如果将其使用到其他标签上,则v-model就是自定义指令了==
v-bind只能实现单向绑定,model中的(vue实例中的数据)数据被更改时,v-bind绑定位置也会实时修改,但是v-bind绑定的位置发生变化时,model中的数据不会发生变化
即:v-model可实现html修改js数据,v-bind只能实现js修改html数据。
v-model.number能够限制数据为number
v-model.trim能够去除前后空格
v-model.lazy懒加载,对于输入框只有按回车或者onblur(失去焦点)才会同步更新
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<input type="text" v-model="number1">
<select v-model="opt">
<option value="+">+option>
<option value="-">-option>
<option value="x">xoption>
<option value="÷">÷option>
select>
<input type="text" v-model="number2">
<button @click="handel">=button>
<input type="text" v-model="result">
div>
body>
<script src="js/vue.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
number1:0,
number2:0,
result:0,
opt:'+',
},
methods:{
handel(){
if(this.opt=="+"){
this.result=parseInt(this.number1)+parseInt(this.number2);
}else if (this.opt="-") {
this.result=parseInt(this.number1)-parseInt(this.number2);
}else if (this.opt="x") {
this.result=parseInt(this.number1)*parseInt(this.number2);
}else if (this.opt="÷") {
this.result=parseInt(this.number1)/parseInt(this.number2);
}
}
}
})
script>
html>
red,big,size是通过类名定义好的style
flag是vue实例中的data字段
<div class="red">传统用法div>
<div :class="['red','big']">通过bind使引号中可以写js代码div>
<div :class="flag?'size':'big'">通过bind使引号中可以写js代码使用三元运算符div>
<div :class="'size'=true">命名默认为Bool值,设为true则生效div>
<div :class="myStyle">通过bind使引号中可以写js代码使用三元运算符div>
<script>
var vue=new Vue({
data:{
myStyle:{'red':true,'size':true,'big':true}
}
})
script>
simpleList是vue实例中的data中的一个数组。
<p v-for="{item,index} in simpleList">
索引:{{index}}
数据:{{item}}
p>
index可要可不要
simplelist里面可以是键值对等其他复杂类型,然后通过.运算符访问其内的数据即可。
<p v-for="(obj,i) in objectList">
{{obj.id}}
{{obj.name}}
p>
数字range
<p v-for="i in 10">p>
会生成从1到10(而不是从0到9)
注意
建议给每个v-for都加上:key,且key不绑定默认生成的index
因为:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<input type="text" v-model="id">
<input type="text" v-model="name">
<p v-for="(obj,i) in objectList">
<input type="checkbox"> id:{{obj.id}}----name:{{obj.name}}
p>
<button @click='handel'>添加button>
div>
body>
<script src="js/vue.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
id:'',
name:'',
objectList:[
{id:1,name:'张三'},
{id:2,name:'张四'},
{id:3,name:'张五'},
{id:4,name:'张六'},
]
},
methods:{
handel(){
var obj={id:this.id,name:this.name}
this.objectList.unshift(obj);
}
}
})
script>
html>
如果先选中任意一个,比如张三,当你通过unshift添加一个新的到前面时,选中框会滑到张四(向下滑落)
绑定key就不会出现这个问题。如果绑定的key是自带的index,也会出现这个问题
v-for="(item,i)in objList"会报错,因为in前面没有空格
v-if和v-show控制标签显示时,v-if会将渲染页面的标签直接进行删除/添加操作,而v-show是更改标签的display属性。
v-show一定会渲染,v-if则不一定,因此,如果用户可能根本就看不到这个,则用v-if。
v-if后可以用v-else和v-else-if,用法类似
new Vue({
el:
data:
directives:{ //自定义指令
change:{ //指令名称
bind:function(){}, //指令绑定到元素
update:function(){}, //更新时回调
unbind:function(){}, //解除时回调
}
}
})
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
id<input type="text" v-model="id">
name
sex<input type="text" v-model="sex">
<button @click="add">添加button>
<table v-for="(obj,index) in objectList" :key="obj.id">
<tr>
<td>IDtd>
<td>nametd>
<td>sextd>
<td>操作td>
tr>
<tr>
<td>{{obj.id}}td>
<td>{{obj.name}}td>
<td>{{obj.sex=='1'?'男':'女'}}td>
<td><button type="button" @click="deleteUser(obj.id)">删除button>td>
tr>
table>
div>
body>
<script src="js/vue.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
id:'',
name:'',
sex:'',
objectList:[
{id:1,name:'张三',sex:'1'},
{id:2,name:'张四',sex:'1'},
{id:3,name:'张五',sex:'0'},
{id:4,name:'张六',sex:'0'},
]
},
methods:{
add(){
var obj={id:this.id,name:this.name,sex:this.sex}
this.objectList.push(obj);
},
deleteUser(objId){
let index = this.objectList.findIndex(item => {
if(item.id===objId){
return true;
}
});
this.objectList.splice(index,1) //从index位置删除一个元素
},
}
})
script>
html>
就像是:将参数传入一个filter管道(函数),出来管道的返回值。
<td>{{obj.sex | myfilter}}td>
<script>
var vue = new Vue({
filters:{
myfilter(sex){
if(sex=='1'){
return '男';
}else{
return 'nv';
}
}
}
})
script>
几个重要点:
created:methods和data的最早使用函数
beforeMount:尚未挂载(渲染)模板
mounted:操作DOM的最早时刻(此时模板已经渲染了,由于Vue实际不用操作DOM,因此此时是进行页面渲染之后的操作)
剩下的方法图中已经说明的很清楚了;
注意,并没有“正在”这个时间段,只有before=>之前,-ed=>之后。
模块化:从代码角度分析的,方便代码分层开发,保证每个模块功能单一
组件化:从UI角度分析的,如分页组件、轮播图组件。
注意,script中使用驼峰命名,在html中必须改成小写,且用 - 连接
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>extend创建组件title>
head>
<body>
<div id="app">
<my-component>my-component>
div>
body>
<script src="js/vue.js">script>
<script>
//创建
var myComponent = Vue.extend({
template:'这是用extend创建的组件'
});
//声明
Vue.component('myComponent',myComponent);
var vue = new Vue({
el:'#app',
data:{
},
})
script>
html>
声明和创建可以合并
Vue.component('myComponent',Vue.extend({
template:'这是用extend创建的组件'
}));
extend也可以省略
Vue.component('myComponent',{
template:'这是用extend创建的组件'
});
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>templatetitle>
head>
<body>
<div id="app">
<my-Component>my-Component>
div>
<template id="mytemp">
<div>
<p>hhhp>
<h1>big headh1>
div>
template>
body>
<script src="js/vue.js">script>
<script>
Vue.component('myComponent',{
template:`#mytemp`
})
var vue = new Vue({
el:'#app',
data:{
},
})
script>
html>
组件本身也是一个对象,因此可以直接创建组件对象
var login={
template:'组件对象
'
}
首先是data,注意,组件的存在是为了提高复用性,而data:{}的写法,会导致多个组件共用一个data,提高了耦合性。因此,组件中的data,必须是一个函数,并且返回一个对象
例子:为什么data必须是函数
Vue.component('mycomponent',{
template:'#temp1',
template:'#temp2',
data(){
return {
msg:0
}
}
})
如果使用这个,则temp1和temp2都共用
组件中的methods跟vue实例中的相同。
将组件定义在vue实例中,则只有与vue实例绑定的el才能使用该组件
<div id="d1">
<my-comp>my-comp>
div>
<div id="d2">
<my-comp>my-comp>
div>
<template id="temp">私有temptemplate>
<script>
var vue = new Vue({
el:'#d1',
components:{
'myComp':{
template:'#temp'
}
}
})
script>
注意自定义component标签的名字需要用引号
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<button @click="flag=true">登录button>
<button @click="flag=false">注册button>
<login v-if="flag">login>
<register v-else>register>
div>
<template id="login">
<div>登录组件
div>
template>
<template id="register">
<div>注册组件
div>
template>
body>
<script src="js/vue.js">script>
<script>
Vue.component('login',{
template:`#login`
})
Vue.component('register',{
template:`#register`
})
var vue = new Vue({
el:'#app',
data:{
flag:true,
},
})
script>
html>
利用占位符component标签绑定component的名字,然后通过点击更改component名字属性实现组件切换。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<button @click="componentName='login'">登录button>
<button @click="componentName='register'">注册button>
<component :is="componentName">component>
div>
<template id="login">
<div>登录组件
div>
template>
<template id="register">
<div>注册组件
div>
template>
body>
<script src="js/vue.js">script>
<script>
Vue.component('login',{
template:`#login`
})
Vue.component('register',{
template:`#register`
})
var vue = new Vue({
el:'#app',
data:{
componentName:'login'
},
})
script>
html>
vue实例是一个父组件,先看vue实例中的数据如何传递给vue实例中的私有组件(即子组件)。
子组件中有一个专门用于访问父组件属性的一个对象:props
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<my-component :parent-msg="msg">my-component>
div>
<template id="temp">
<div>
<p>{{msg}}p>
<p>{{parentMsg}}p>
div>
template>
body>
<script src="js/vue.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
msg:'我是父组件中的数据'
},
components:{
'my-component':{
template:'#temp',
data(){
return {
msg:'我是子组件中的数据'
}
},
props:{
'parent-msg':{
type:String,
default:null
}
}
}
}
})
script>
html>
关键逻辑:
props可以定义为数组props:[‘parentMsg’],当它定义为对象时,是标准写法。
注意凡是标签内的驼峰式都改成-连接,凡是{{}}中的都改成驼峰
props中的数据是只读的,不要用子组件去更改父组件中的数据
根据父组件向子组件传递属性的做法,与传递属性有点不太一样,这个比较绕
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<p>{{msg}}p>
<my-component @parent-change="changeMsg">my-component>
div>
<template id="temp">
<div>
<button @click="there_is_son_method">修改button>
div>
template>
body>
<script src="js/vue.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
msg:'我是父组件中的数据'
},
methods:{
changeMsg(){
this.msg="被修改了"
}
},
components:{
'my-component':{
template:'#temp',
methods:{
there_is_son_method(){
this.$emit('parent-change')
}
}
}
}
})
script>
html>
关键步骤
(个人理解)父子组件间的数据传递,都是通过子组件声明父组件属性/方法,然后在html代码中实现父子属性/方法的绑定
$emit表示声明使用父组件的方法,第一个参数是假定的父组件名称,后面的都是参数
首先学习ref
下面这个是js的写法,操作dom元素
<div id="div1">div>
<script>
let data = document.getElementById("div1").innerText;
script>
下面是vue操作dom元素的方法
<div ref="div1">div>
<script>
let data = this.$refs.div1.innerText
script>
可以让父组件通过ref找到子组件,然后调用子组件的方法
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<button @click="parentFunc">父组件调用子组件button>
<my-component ref="refname">my-component>
div>
<template id="temp">
template>
body>
<script src="js/vue.js">script>
<script>
var vue = new Vue({
el:'#app',
methods:{
parentFunc(){
console.log("父组件方法")
this.$refs.refname.childFunc()
}
},
components:{
'my-component':{
template:'#temp',
methods:{
childFunc(){
console.log("子组件被调用")
}
}
}
}
})
script>
html>
关键步骤:
需要使用vue-router包,当导入这个包之后,window全局就有了VueRouter这个构造函数。
什么是路由
后端:对于普通的网站,所有超链接都对应一个url,指向服务器资源
前端:对于单页面应用,主要通过url的#(hash)来实现不同页面的切换,通过hash实现的(相当于a标签)
每个路由是一个对象(用{}定义),每个对象都包含两个属性:path:表示路由的url,component:表示路由的跳转目标组件
步骤:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<router-link to="/login" tag="button">登录router-link>
<router-link to="/register">注册router-link>
<router-view>router-view>
div>
<template id="login"><div>登录组件div>template>
<template id="register"><div>注册组件div>template>
body>
<script src="js/vue.js">script>
<script src="js/vue-router.js">script>
<script>
var login = {
template:'#login'
}
var register = {
template:'#register'
}
let routerObj = new VueRouter({
routes:[
{path:'/',redirect:'/login'},//这个不是重定向请求,仅仅是重定向组件
{path:'/login',component:login},
{path:'/register',component:register},
]
})
var vue = new Vue({
el:'#app',
router:routerObj
})
script>
html>
前后端未分离时:
前后端分离(Vue):
方法一:使用路由时/login?name=zs&psw=123的形式传参,然后$route.query.name获取
方法二:定义路由时设置 /register/:name/:psw ,使用router-link时/register/ls/123,然后$route.params.name获取
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<router-link to="/login?name=zs&psw=123" tag="button">登录router-link>
<router-link to="/register/ls/123">注册router-link>
<router-view>router-view>
div>
<template id="login"><div>登录组件
<P>{{$route.query.name}}P>
<P>{{$route.query.psw}}P>
div>template>
<template id="register"><div>注册组件
<p>{{$route.params.name}}p>
<p>{{$route.params.psw}}p>
div>template>
body>
<script src="js/vue.js">script>
<script src="js/vue-router.js">script>
<script>
var login = {
template:'#login'
}
var register = {
template:'#register'
}
let routerObj = new VueRouter({
routes:[
{path:'/',redirect:'/login'},//这个不是重定向请求,仅仅是重定向组件
{path:'/login',component:login},
{path:'/register/:name/:psw',component:register},
]
})
var vue = new Vue({
el:'#app',
router:routerObj
})
script>
html>
routers里面使用children再声明路由,就是路由嵌套。
children与path同级
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<router-view>router-view>
div>
<template id="index">
<div>
<h1>首页h1>
<router-link to="index/login" tag="button">点击登录router-link>
<router-view>router-view>
div>
template>
<template id="login">
<div>
<p>登录组件p>
<router-link to="login/success" tag="button">提交登录router-link>
<router-view>router-view>
div>
template>
<template id="success">
<div>
<p>登录成功p>
div>
template>
body>
<script src="js/vue.js">script>
<script src="js/vue-router.js">script>
<script>
var login = {
template:'#login'
}
var success = {
template:'#success'
}
var index = {
template:'#index'
}
let routerObj = new VueRouter({
routes:[
{path:'/',redirect:'/index'},//这个不是重定向请求,仅仅是重定向组件
{path:'/index',component:index,
children:[{
// 斜杠/表示从根路径匹配,而子路由不能加/,而且实际上会默认给子路由加上父路由
path:'login',component:login,
children:[{
path:'success',component:success
}]
}]
}]
})
var vue = new Vue({
el:'#app',
router:routerObj
})
script>
html>
注意问题:
router是VueRouter的实例,是全局对象,包含了所有路由的一些关键对象和属性;
route是一个特定路由对象,是局部对象,比如监听器监控路由的时候就是用route,表示监控当前跳转的路由。
也就是:通过js实现路由跳转
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
用户名<input type="text" v-model="name"><br>
密码<input type="password" v-model="psw"><br>
<button @click="toGetLogin">get登录button>
<br>
用户名<input type="text" v-model="name"><br>
密码<input type="password" v-model="psw"><br>
<button @click="toPostLogin">Post登录button>
<router-view>router-view>
div>
<template id="login"><div>
<p>登录成功p><br>
<P>欢迎使用path+query方式:{{$route.query.name}}P>
<P>欢迎使用name+params方式:{{$route.params.name}}P>
div>template>
body>
<script src="js/vue.js">script>
<script src="js/vue-router.js">script>
<script>
var login = {
template:'#login'
}
let routerObj = new VueRouter({
routes:[
{path:'/',redirect:'/login'},//这个不是重定向请求,仅仅是重定向组件
{name:'login',path:'/login',component:login},
]
})
var vue = new Vue({
el:'#app',
data:{
name:'张三',
psw:'123456'
},
methods:{
toGetLogin(){
this.$router.push({
path:'/login',
query:{
name:this.name,
psw:this.psw
}
})
},
toPostLogin(){
this.$router.push({
name:'login',
params:{
name:this.name,
psw:this.psw
}
})
}
},
router:routerObj
})
script>
html>
知识点:
假设有对象:firstname、lastname、fullname,如何实现:当firstname和lastname改变时,同步改变fullname?
data中不能直接实现fullname:firstname+lastname
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<div>firstname: {{firstname}}div>
<div>lastname: {{lastname}}div>
<div>fullname: {{fullname}}div>
<input type="text" v-model="firstname">
<br>
<input type="text" v-model="lastname">
<br>
<input type="text" v-model="fullname">
div>
body>
<script src="js/vue.js">script>
<script src="js/vue-router.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
fullname:'',
},
watch:{
firstname(newVal,oldVal){ //监听器默认参数,第一个表示监听对象的新值,第二个为旧值
this.fullname = newVal+this.lastname
},
lastname(newVal,oldVal){
this.fullname = this.firstname+newVal
}
}
})
script>
html>
凡是’firstname’:funtion(){}都可以简写为firstname(){}
使用监听器的好处:
html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<router-view>router-view>
div>
<template id="index">
<div>
<h1>首页h1>
<router-link to="index/login" tag="button">点击登录router-link>
<router-view>router-view>
div>
template>
<template id="login">
<div>
<p>登录组件p>
<router-link to="login/success" tag="button">提交登录router-link>
<router-view>router-view>
div>
template>
<template id="success">
<div>
<p>登录成功p>
div>
template>
body>
<script src="js/vue.js">script>
<script src="js/vue-router.js">script>
<script>
var login = {
template:'#login'
}
var success = {
template:'#success'
}
var index = {
template:'#index'
}
let routerObj = new VueRouter({
routes:[
{path:'/',redirect:'/index'},//这个不是重定向请求,仅仅是重定向组件
{path:'/index',component:index,
children:[{
// 斜杠/表示从根路径匹配,而子路由不能加/,而且实际上会默认给子路由加上父路由
path:'login',component:login,
children:[{
path:'success',component:success
}]
}]
}]
})
var vue = new Vue({
el:'#app',
router:routerObj,
watch:{
'$route.fullPath'(newVal,oldVal){
console.log('用户从',oldVal,'跳转到',newVal)
}
}
})
script>
html>
注意看watch部分
通过路由监听,可以实现后端拦截器的功能:监听路由的url是否为登录url,如果不是,则检查用户是否登录过,若没登陆过,则重定向到登录路由。
用监听器实现数据拼接太麻烦了,有更好的方式
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<div>firstname: {{firstname}}div>
<div>lastname: {{lastname}}div>
<div>fullname: {{sumName}}div>
<input type="text" v-model="firstname">
<br>
<input type="text" v-model="lastname">
<br>
<input type="text" v-model="sumName">
div>
body>
<script src="js/vue.js">script>
<script src="js/vue-router.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
firstname:'',
lastname:'',
fullname:'',
},
computed:{
sumName(){
return this.firstname+this.lastname
}
}
})
script>
html>
注意:
还可以将computed当做对象使用,调用他的get和set方法。
get:当计算computed目标时调用
set:当设置computed目标时调用
需求:
计算器a+b=c,c为计算属性,要求更改ab时,得出c----get。
要求更改c的时候,得出a和b----set
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<input type="text" v-model.number="a">
+
<input type="text" v-model.number="b">
=
<input type="text" v-model.number="sum">
div>
body>
<script src="js/vue.js">script>
<script>
var vue = new Vue({
el:'#app',
data:{
a:0,
b:0,
c:0,
},
computed:{
sum:{
get(){
return this.a + this.b
},
set(val){
this.a=val-this.b;
this.b=val-this.a;
}
}
}
})
script>
html>
node是JavaScript的运行时环境(类似于Tomcat是Java的一个运行环境),node为js提供了更强大的操作方式,
如:
但不会真的用node写后台,更多的是用它来写前端配置,如:跨域代理
此处node仅用于提供编写vue的环境。
初步使用,官网下载node,一路下一步即可。然后将nodejs整个文件夹加入到环境变量中
然后在cmd中查看node是否配置成功
node -v
并查看npm版本
npm -v
npm是node提供的一个包管理工具,类似于maven。
通过npm安装依赖包,就不需要在页面上使用script标签引入了。
npm配置淘宝镜像:
npm config set registry https://registry.npm.taobao.org
问:网页中的静态文件过多会怎样?
答:静态文件需要发起二次请求来引入,过多的时候会导致网页很慢很卡
问:网页中有哪些静态文件?
答:js、css、图片、
如何解决上述问题?
合并、压缩、精灵图(将小图合并为一张图,因此只需要请求一次)、base64编码、webpack
import 导入
export导出
vue不像java,需要使用某个模块时,不仅仅需要import导入该模块,而且需要在该模块中将所需对象export向外暴露,否则import是无法生效的。
export default一个模块有且仅有一个
创建一个空文件夹webpackStudy,用VSCode打开该文件夹
打开cmd终端,执行npm init,后面出现的各种初始化信息按需选择,我只填了个test项目名,其中默认的入口文件是index.js,然后一直回车到底,生成对应的package.json文件,用于打包配置。
安装webpack,先全局环境,后开发环境(可以先用webpack -v查看全局是否安装过)
webpack -v
npm i webpack -g
npm i webpack --save-dev
可以看到package.json中的devDependencies已经导入了webpack
创建src文件夹,(src表示源码目录),在scr下创建入口文件index.js和index.html (node_modules是node的依赖包,不要管也不要动)
alert('我是index');
我用的 !+回车 自动生成的html代码
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>indextitle>
head>
<body>
<h1>我是首页h1>
body>
html>
根目录创建webpack.config.js文件
//导入内置的路径处理模块
const path = require('path');
const config = {
entry: path.resolve(__dirname,'src/index.js'),
output: {
// path: path.resolve(__dirname,'dist'),//输出路径,默认就是dist
filename:'bundle.js' //输出文件名,默认index.js
},
};
module.exports = config;
意思是配置入口文件,
更改终端启动命令,在package.js中将scripts修改为如下
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev":"webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.41.5"
}
}
scripts用于配置npm run命令,上述更改意思是当npm run dev时,等价于npm run webpack,简化代码,可以自定义
执行npm run dev查看效果,控制台会要求下载webpack-cli,输入yes进行安装。随后可以看到多了dist文件夹,里面有打包好的main.js,但是,并没有将index.html打包,因为webpack只支持js,因此需要插件
安装webpack生成html文件的插件:
npm i html-webpack-plugin --save-dev
在webpack.config.js中声明使用该插件
//导入内置的路径处理模块
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {
entry: path.resolve(__dirname,'src/index.js'),
output: {
// path: path.resolve(__dirname,'dist'),//输出路径,默认就是dist
filename:'bundle.js' //输出文件名,默认index.js
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'src/index.html'),
})
],
};
module.exports = config;
然后npm run dev,可以看到dist下生成了index.html,打开该index,能够看到“我是首页”的h1标题,也能看到alert弹窗
配置实施热部署
安装 npm i webpack-dev-server --save-dev
将原本package中的scripts中的"dev":"webpack-dev-server --open --hot " 后面还可以跟 --port 8888实现更改端口,默认8080
运行npm run dev
注意webpack-dev-server不会实现实时打包,而是存放在内存中,当编码完毕再执行webpack进行打包
配置打包css文件:
给index.html中的h1加一个class=“my”,在src下创建css/index.css,里面写
.my{
color: red
}
在index引入这个css文件
alert('我是index');
import './css/index.css'
然后运行项目会发现没作用,打开控制台报了一堆错误,还是那句话:因为webpack只支持js。因此需要安装loader
npm i --save-dev style-loader css-loader
在webpack.config.js中创建models节点,装载loader
//导入内置的路径处理模块
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {
entry: path.resolve(__dirname,'src/index.js'),
output: {
// path: path.resolve(__dirname,'dist'),//输出路径,默认就是dist
filename:'bundle.js' //输出文件名,默认index.js
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'src/index.html'),
})
],
module:{//注册第三方模块
rules:[
{test: /\.css$/,use: ['style-loader','css-loader']}//配置处理css
]
}
};
module.exports = config;
然后运行项目发现css起作用了。
(如果是UI框架,则直接在index.html中导入即可)
开始vue编写,将index.js中的代码全部注释
安装vue和loader
npm -i vue vue-loader vue-template-compiler --save-dev
在webpack.config.js中注册组件和loader(仅仅展示了关键代码)
const VueLoaderPlugin = require('vue-loader/lib/plugin');
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'src/index.html'),
}),
new VueLoaderPlugin(),
],
module:{//注册第三方模块
rules:[
{test: /\.css$/,use: ['style-loader','css-loader']},//配置处理css
{test: /\.vue$/,use: 'vue-loader'},//配置处理vue
]
}
index.html中给一个vue容器
<div id="app">div>
创建template/login.vue
<template>
<div>
<h1>登录组件</h1>
<div>{{msg}}</div>
</div>
</template>
<script>
export default{
data(){
return{
msg: 'Hello login'
}
},
methods:{
},
filters:{
},
computed:{
}
}
</script>
<style scoped>
/* 必须加scoped,表示仅在本组件中生效,否则会产生样式污染 */
</style>
在index.js中导入
import Vue from 'vue/dist/vue.esm.js'
import login from './templates/login.vue'
var vm = new Vue({
el: '#app',
rander: c => c(login), //意思是,传入的是一个函数c,返回值是c(login),注册组件并渲染
})
vue路由的使用:
安装路由
npm i vue-router --save-dev
src下创建router/index.js
import Vue from 'vue/dist/vue.esm.js'
import login from '../templates/login.vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
var router = new VueRouter({
routes:[
{path: '/login', component: login}
]
})
export default router
src下的index.js导入该路由
import Vue from 'vue/dist/vue.esm.js'
import app from './app.vue'
import router from './router'
var vm = new Vue({
el: '#app',
rander: c => c(app), //意思是,传入的是一个函数c,返回值是c(app),注册组件并渲染
router: router,
})
// vue.config.js 配置说明
// 这里只列一部分,具体配置参考文档
module.exports = {
// baseUrl :'/'
// 将部署应用程序的基本URL
// 默认情况下,Vue CLI假设您的应用程序将部署在域的根目录下。
// https://www.my-app.com/。如果应用程序部署在子路径上,则需要使用此选项指定子路径。例如,如果您的应用程序部署在https://www.foobar.com/my-app/,集baseUrl到'/my-app/'.
// baseUrl: '/',
// lintOnSave:{ type:Boolean default:true } 问你是否使用eslint
lintOnSave: false,
// productionSourceMap:{ type:Bollean,default:true } 生产源映射
// 如果您不需要生产时的源映射,那么将此设置为false可以加速生产构建
productionSourceMap: false,
// devServer:{type:Object} 3个属性host,port,https
// 它支持webPack-dev-server的所有选项
devServer: {
port: 8085, // 端口号
open: true, //配置自动启动浏览器
// proxy: 'http://localhost:4000' // 配置跨域处理,只有一个代理
proxy: {
'/': {
target: 'http://localhost:8080',
ws: true,
changeOrigin: true
}
}, // 配置多个代理
}
}
import axios from 'axios'
const service = axios.create({
baseURL: '/',
timeout: 5000 // 默认请求超时时间5s
})
// request 拦截器
service.interceptors.request.use(
config => {
return config
},
error => {
return Promise.reject(error)
}
)
// response 拦截器
service.interceptors.response.use(
response => {
const res = response.data
return res
},
error => {
}
)
export default service
import request from '../utils/request'
const group_name = 'department'
export default {
departmentList() { //查询列表接口
return request({
//反引号中可以使用模板表达式,可以任意换行
url: `/${group_name}/departmentList`,
method: 'get'
})
},
save(department){ //保存接口
return request({
url:`/${group_name}/save`,
method: 'post',
data:department
})
}
}
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
方式一:通过路由访问该组件
登录
方式二:通过导入组件访问(引入、声明、使用)
这里使用组件
跨域:当请求方和响应方的ip或端口不同时,就是跨域;出于安全起见,浏览器不允许跨域请求
解决方案:
PC端:
移动端
var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
list.push(obj) 将obj添加到数组后面
list.unshift(obj) 将obj添加到数组前面
不要使用关键字给函数命名,如delete
学习一下ES6的语法。
null表示有这个对象,但是为空
undefined表示压根没有这个对象
!回车:生成html框架
select>option4:生成有4个选项的select标签
table>tr3>td*5:生成三行五列的table