用户管理 权限管理 商品管理 订单管理 系统设置
视图层->监听dom->数据层
数据层->根据数据绑定->视图层
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YYIQxm7Z-1596001043673)(/Users/limboaaa/Library/Application Support/typora-user-images/截屏2020-07-26 上午9.30.20.png)]
<div>
{{msg}}
div>
new Vue({
el:'',
data:{
msg:'1'
}
})
el:元素的挂载位置
data:模型数据
{{}}:差值表达式->将数据填充到HTML标签中,支持基本的计算操作。
自定义的属性:在标签上定义的data-xxxx/abc = ’ ';
作用:解决差值表达式闪动问题
1.提供样式
[v-cloak]{
display:none;
}
2.在差值表达式所在的标签中添加v-cloak
2.在差值表达式所在的标签中添加v-cloak
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EkZPV8XF-1596001043675)(/Users/limboaaa/Desktop/截屏2020-07-26 上午8.54.22.png)]
描述:向页面中插入一个纯文本
描述:填充HTML片段
**描述:**显示原始信息,跳过编译过程
**描述:**只编译一次,显示内容后不再具有数据响应式功能
应用场景:显示的信息后续不必再修改,可以使用v-once,可以提高性能。
<div v-once>{{msg}}div>
v-model的本质,就是v-bind:value = ‘’,然后Input监听事件,将input的内容复制给该属性;
完全体:
简写:
.stop 阻止冒泡
<div id="app">
{{num}}
<button @click.stop='handle1'>点击1button>
div>
div>
.prevent 阻止默认行为
<a href="https://www.baidu.com" @click.prevent='handle'>跳转至百度a>
键盘:enter事件/ delete事件
用户名:
密码:
自定义按键修饰符
全局变量:
config.keyCodes对象
Vue.config.keyCodes.xx = keynum;
使用:
xx:别名
keynum:->可使用event.keyCode 获取对应键位的值
属性绑定
v-bind指令
完全体:
a>
简写形式:
a>
样式绑定
默认的class如何处理呢?->保留
数组可以结合对象一起使用
<div v-bind:class="[activeClass,errorClass,{test:isTest}]">div>
使用:
<Style>
.active {
border: 1px solid red;
width: 100px;
height: 100px;
}
.error{
background-color: yellow;
}
Style>
// 对象语法
<div v-bind:class="{active:isActive,error:isError}">div>
// 数组语法
<div v-bind:class="[activeClass,errorClass]">div>
// 对象简化操作语法
<div v-bind:class="objClasses">div>
// 数组简化操作语法
<div v-bind:class="arrClasses">div>
// 内联Style
<div v-bind:style="{border:borderStyle,width:widthStyle,height:heightStyle}">div>
// 简化内联Style
div>
data() {
return {
/*对象语法 开始**/
isActive:true,
isError:false
/*对象语法 结束**/
-----------------------------------------------------
/*对象简化操作 开始**/
objClasses:{
active:true,
error:true
}
/*对象简化操作 结束**/
-----------------------------------------------------
/*数组语法 开始**/
activeClass:'active',
errorClass:'error'
/*数组语法 结束**/
-----------------------------------------------------
/*数组简化操作 开始**/
arrClasses:['active','error']
/*数组简化操作 结束**/
-----------------------------------------------------
/*内联样式 开始**/
borderStyle:'1px solid blue',
widthStyle:100px,
heightStyle:200px
/*内联样式 结束**/
-----------------------------------------------------
/*简化内联样式 开始**/
objStyle{
border:'1px solid blue',
width:100px,
height:200px
}
/*简化内联样式 结束**/
}
分支结构
- v-if
- v-else
- V-else-if
- v-show
v-if与v-show的区别
- V-if 控制元素是否渲染到页面
- V-show 控制元素是否显示(display:none/’ ')
循环结构
V-for
<ul>
{{item}}li>
{{item}}{{index}}li>
{{item.eName}}------{{item.cName}}li>
{{item}}li>
ul>
data() {
return {
//数组
fruits:['apple','orange','banana']
// 数组对象
user:[{eName:'jack',
cName:"杰克"
},{
eName:'john',
cName:'路西'
},{
eName:'john',
cName:'约翰'
}]
}
}
# item:自定义变量,迭代的元素。
分支循环结构
v-for 遍历对象
li>
v-for 结合v-if
li>
表单域修饰符
- number:转换为数值
- Trim:去掉开始和结尾的空格
- lazy:将input时间切换为change事件
// 输入框失去焦点触发,使用场景:注册用户名,会检测是否已经存在,需要获取该输入框数据
自定义指令
// 全局指令
Vue.directive('指令名'{
inserted:function(el){
// 获取元素的焦点
el.指令名()
}
})
// 局部指令
directives:{
指令名称:{
insered:function(el){
el.指令名称
}
}
}
// 使用方式
<input v-指令名>
计算属性
将复杂的计算逻辑抽取出来,使模板内容更加简洁。
计算属性与方法的区别?
- 计算属性是基于他们的依赖(data中的数据)进行缓存的(相同的逻辑只执行一次,并将执行的结果缓存)
- 方法不存在缓存
<div id="app">
{{msg}}
{{reverseString}}
div>
computed: {
reverseString:function(){
// 有返回值 需要return
return this.msg.split('').reverse().join('')
}
}
侦听器
描述:数据变化会触发侦听器锁绑定的方法
使用场景:数据变化时执行异步或开销较大的操作
var vm = new Vue({
el: '#app',
data() {
return {
firstName:'张',
lastName:'桂源',
fullName:'张桂源',
}
},
// 侦听器
watch: {
// 侦听的属性名与data中的属性名一致
// val:变化后的数据
firstName:function(val){
this.fullName = val + ' ' + this.lastName
},
lastName:function(val){
this.fullName = this.firstName + ' ' + val
}
},
})
过滤器
作用:格式化数据,比如讲字符串格式化为首字母大写,将日期转化为指定格式。
// 创建一个全局的过滤器
Vue.filter('filter1',function(val){
return val.charAt(0).toUpperCase()+val.slice(1)
})
// 使用方式
{{msg | filter1}}
// 可以多个条件
{{msg | filter1 | filter2}}
// 可以对绑定的数据进行过滤
div>
// 局部filter
filters:{
filter1:function(){
},
filter2:function(){
}
}
// 时间格式化
{{date | dateFormat('yyyy-MM-dd')}}
// 第二个形参为传递的参数
Vue.filter('dateFormat',function(value,arg){
// 时间转换格式
})
变异方法(修改原有数据)
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
替换数组(生成新的数组)
filter()、concat()、slice() 不会改变原数组,都返回一个心的数组
vm.list[1] = 'lemon' // 通过这种下表修改属性值,不具备响应式
Vue.set(vm.list,index,'lemon') // 具备响应式
vm.$set(vm.list,index,'lenmon') // 具备响应式
// 对象
vm.$set(vm.info,'gender','female');// 具备响应式
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<script type="text/javascript" src="./js/vue.js">script>
<script type="text/javascript" src="./js/vue-router.js">script>
<Style>
.active {
border: 1px solid red;
width: 100px;
height: 100px;
}
.error {
background-color: yellow;
}
Style>
<body>
<div id="app">
<div>
编号:<input class="form-control" type="text" v-model='id' :disabled="flag">
书名:<input class="form-control" type="text" v-model='name'>
<span>{{total}}span>
<button @click='handle' :disabled='butFlag'>添加button>
div>
<table>
<tr :key='item.id' v-for='(item,index) in books'>
<td>{{item.id}}td>
<td>{{item.name}}td>
<td>{{item.now}}td>
<td>
<a href="" @click.prevent='edit(item.id)'>修改a>
<span @click.prevent>|span>
<a href="" @click.prevent='del(item.id)'>删除a>
td>
tr>
table>
div>
body>
<script>
// 第二个形参为传递的参数
Vue.filter('dateFormat', function (value, arg) {
// 时间转换格式
})
var vm = new Vue({
el: '#app',
data: {
id: '',
name: '',
flag: false,
butFlag: false,
books: [
]
},
computed: {
total: function () {
return this.books.length
}
},
watch: {
name: function (val) {
var flag = this.books.some(function (item) {
return item.name == val;
});
if (flag) {
this.butFlag = true;
} else {
this.butFlag = false;
}
}
},
mounted() {
this.books = [{
id: 1,
name: '围城'
},
{
id: 2,
name: '三体'
},
{
id: 3,
name: '白夜行'
}]
},
methods: {
handle: function () {
if (this.flag) {
// 修改操作
this.books.some((item) => {
if (item.id == this.id) {
item.name = this.name
return true;
}
})
this.flag = false
} else {
// 添加
var book = {};
book.id = this.id;
book.name = this.name;
this.books.push(book);
}
// 将文本清空
this.id = '';
this.name = '';
},
edit: function (id) {
this.flag = true;
var book = this.books.filter(function (item) {
return item.id == id;
})
this.id = book[0].id;
this.name = book[0].name;
},
del: function (id) {
this.books = this.books.filter(function (item) {
return item.id != id
})
}
},
})
script>
html>
组件化开发
- 命名方式 短横线:xxx-xxx 驼峰式:HelloWorld ,
- 组件模板必须是唯一的根节点
- 组件data 必须是一个函数(组件可复用且互不影响)
// 使用
<button-count>button-count>
<button-count>button-count>
<button-count>button-count>
// 全局组件注册
Vue.component('button-count',{
// 组件数据 必须是一个函数
data:function(){
return {
count :0
}
},
// 组件模板内容
template:
`
父组件向子组件传值
-
组件内部通过Props接受传递过来的值
- props中使用驼峰形式,模板中需要使用短横线的形式
- 字符串形式的模板中没有这个限制(template中)
- props传递原则:
Vue.component('menu-item',{
props:['title'],
temelate:
`
<div>
{{title}}
div>
`
})
-
父组件通过属性将值传递给子组件
menu-item>
menu-item>
子组件向父组件传递信息
- 子组件通过自定义事件向父组件传递信息
`
- 父组件监听子组件的事件
menu-item>
子组件向父组件传值
`
父组件监听子组件的事件
menu-item>
非父子组件间传值
- 单独的事件中心管理组件间的通信
var eventHub = new Vue()
- 监听事件与销毁事件
eventHub.$on('add-todo',addTodo)
eventHub.$off('add-todo') // 一般在vue实例中销毁
- 触发事件
eventHub.$emit('add-todo',id)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aqhM5kIn-1596001043677)(/Users/limboaaa/Library/Application Support/typora-user-images/截屏2020-07-27 下午4.52.04.png)]
组件插槽的作用
父组件向子组件传递内容
<slot>content-textslot>
购物车案例
var CartTitle = {
props: ['uname'],
template: `
{{uname}}的商品
`
}
var CartList = {
props: ['list'],
template: `
`,
methods: {
changeNum: function(id, event){
this.$emit('change-num', {
id: id,
type: 'change',
num: event.target.value
});
},
sub: function(id){
this.$emit('change-num', {
id: id,
type: 'sub'
});
},
add: function(id){
this.$emit('change-num', {
id: id,
type: 'add'
});
},
del: function(id){
// 把id传递给父组件
this.$emit('cart-del', id);
}
}
}
var CartTotal = {
props: ['list'],
template: `
总价:{{total}}
`,
computed: {
total: function() {
// 计算商品的总价
var t = 0;
this.list.forEach(item => {
t += item.price * item.num;
});
return t;
}
}
}
Vue.component('my-cart',{
data: function() {
return {
uname: '张三',
list: [{
id: 1,
name: 'TCL彩电',
price: 1000,
num: 1,
img: 'img/a.jpg'
},{
id: 2,
name: '机顶盒',
price: 1000,
num: 1,
img: 'img/b.jpg'
},{
id: 3,
name: '海尔冰箱',
price: 1000,
num: 1,
img: 'img/c.jpg'
},{
id: 4,
name: '小米手机',
price: 1000,
num: 1,
img: 'img/d.jpg'
},{
id: 5,
name: 'PPTV电视',
price: 1000,
num: 2,
img: 'img/e.jpg'
}]
}
},
template: `
`,
components: {
'cart-title': CartTitle,
'cart-list': CartList,
'cart-total': CartTotal
},
methods: {
changeNum: function(val) {
// 分为三种情况:输入域变更、加号变更、减号变更
if(val.type=='change') {
// 根据子组件传递过来的数据,跟新list中对应的数据
this.list.some(item=>{
if(item.id == val.id) {
item.num = val.num;
// 终止遍历
return true;
}
});
}else if(val.type=='sub'){
// 减一操作
this.list.some(item=>{
if(item.id == val.id) {
item.num -= 1;
// 终止遍历
return true;
}
});
}else if(val.type=='add'){
// 加一操作
this.list.some(item=>{
if(item.id == val.id) {
item.num += 1;
// 终止遍历
return true;
}
});
}
},
delCart: function(id) {
// 根据id删除list中对应的数据
// 1、找到id所对应数据的索引
var index = this.list.findIndex(item=>{
return item.id == id;
});
// 2、根据索引删除对应数据
this.list.splice(index, 1);
}
}
});
var vm = new Vue({
el: '#app',
data: {
}
});
前后端交互
要保证多个异步请求顺序:需要嵌套ajax
Promise
常用APi:
实例方法
- p.then()得到异步任务的正确结果
- p.catch()得到异常信息
- p.finally()成功与否都会执行(尚且不是正式标准)
对象方法
- Promise.all()并发处理多个异步任务,所有任务都执行完成才能得到结果
- Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果,其他任务仍执行,只是不关心其他任务执行的状态。
异步编程的一种解决方案,从语法上讲,Promise是一个对象,它可以获取异步操作消息
使用Promise 主要有一下好处:
- 可以避免多层异步调用嵌套问题
- Promise对象提供简洁的API,使得控制异步操作更加容易
Promise基本用法
- 实例化Promise对象,构造函数中传递函数,该函数中用于处理异步任务
- resolve和reject 两个参数用于处理成功和失败两种情况,并通过p.then获取处理结果。
var p = new Promise(function(resolve.reject){
//成功时调用
resolve()
//失败时调用
reject()
});
p.then(function(ret){
// 从resolve 得到正常结果
},
function(ret){
// 从reject 得到错误信息
}
)
实例:
var promise = new Promise(function(resovle,reject){
var flag = false;
if(flag){
// 正确的逻辑
resovle('ok')
}else{
// 错误的逻辑
reject('fuck!')
}
});
promise.then(function(msg){
console.log(msg)
},
function(msg){
console.log(msg)
})
-----------------------------------------------------------------
function queryData(url){
var promise = new Promise(resolve,reject){
var xhr = new XMLHttpRequest();
if(xhr.readyState != 4)return;
if(xhr.readyState == 4 && xhr.status == 200){
resolve('success');
}else{
reject('error')
}
xhr.open('get',url);
xhr.send(null)
}
return p;
}
queryData('url')
.then(function(msg){
// 正常时
},
function(msg){
// 异常时
}
)
// 异常时
.catch(function(msg){
})
var p1 = queryData(url)
var p2 = queryData(url)
var p3 = queryData(url)
// Promise.all()并发处理多个异步任务,所有任务都执行完成才能得到结果
Promise.all([p1,p2,p3]).then(function(result){
console.log(result)
})
// Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果,其他任务仍执行,只是不关心其他任务执行的状态。
Promise.race([p1,p2,p3]).then(function(result){
console.log(result)
})
then参数中的函数返回值
- 返回Promise实例对象
- 返回该实例对象会调用下一个then
- 返回普通值
- 返回的普通值会直接传递给下一个then,通过then参数中函数的参数接収该值
接口调用fetch用法
基本特性:
- 更加简单的数据获取方式,功能更强大,更灵活,可以看做是xhr的升级版
- 基于Promise实现
响应数据格式:
- text():将返回体处理成字符串类型
- json():将返回结果和JSON.parse(responseText)一样
常用配置选项
- method(string):Htpp的请求方法,[GET/POST/PUT/DELETE]
- body(string):Http的请求参数
- headers(Object):Http的请求头,默认为{}
语法结构:
fetch(url).then(fn2)
.then(fu3)
.then(fu3)
...
.then(fn)
fetch('/abc').then(data=>{
return data.text();// fetch 特有的text,这里返回的是一个promise实例对象,用于获取后台的数据
}).hten(ret=>{
// 注意! 这里得到的才是最终的数据
console.log(ret)
})
#配置选项 GET
fetch('/abc?id = 123'|rest风格:'/abc/123',{
method:'get'
})
#rest接收
app.get('/abc/:id',(rqs,rps))
#配置选项 POST
fetch('/abc?id = 123'|rest风格:'/abc/123',{
method:'post',
body:'name = list&pwd = 123',
headers:{
'Content-Type':'application/x-www-form-urlencoded'
}
})
#配置选项 POST ->JSON
fetch('/abc?id = 123'|rest风格:'/abc/123',{
method:'post',
body:JSON.stringify({
name:'jack',
pwd:'456'
}),
headers:{
'Content-Type':'application/json'
}
})
axios
基于Promise用于浏览器和Node.js的Http客户端
特性
- 支持浏览器和Node.js
- 支持promise
- 能拦截请求和响应
- 自动转换JSON数据
响应结果的主要特性
- data: 实际响应回来的数据
- Headers:响应头信息
- Status:响应状态码
- statusText:响应状态信息
axios的全局配置
Axios.defaults.timeout = 3000; //设置超时
axios.defaults.baseURL = //默认地址
axios.defaults.headers[‘mytoken’] = ‘11asdasdklh’ // 设置请求头
axios.get('/adata')
.then(ret=>{
// data属性名称是固定的,用于获取后台响应的数据
console.log(ret.data)
})
//配置请求头信息,对于跨域来讲,此操作需要配置该请求头信息。
axios.defaults.headers['mytoken'] = 'myToken';
// 配置请求的基准URL地址
axios.defaults.baseURL = ’http://localhost:8090‘;
// 会自动拼接该baseUrl
axios.get('axios-json')
.then(function(ret){
console.log(ret.data)
})
常用API
1.GET传递参数
- 通过URL传递参数
- 通过params选项传递参数
#通过url传参
axios.get('/adate?id=123')
.then(ret=>{
console.log(ret.data)
})
#通过params传参
axios.get('/adate',{
//对象
params:{
id:789
}
}).then(function(ret){
console.log(ret.data)
})
#响应请求
app.get('/adata',(req.res)=>{
res.send(req.query.id)
}
#result请求
app.get('adata/:id',(req,res)=>
res.send(req.params.id)
)
2.DELETE传递参数
#通过url传参
axios.delete('/adate?id=123')
.then(ret=>{
console.log(ret.data)
})
#params传参
axios.delete('/adate',{
//对象
params:{
id:789
}
}).then(function(ret){
console.log(ret.data)
})
#响应请求
app.delete('/adata',(req.res)=>{
res.send(req.query.id)
}
3.POST参数传递
通过选项传递参数(默认传递的是json格式数据)
axios.post('/adata',{
uname:'tom',
pwd:123
}).then(ret=>{
console.log(ret.data)
})
#响应请求
app.post('/adata',(req.res)=>{
res.send(req.body.uname+'-----'req.body.pwd)
}
表单形式参数
通过URLSearchParams传递参数(application/x-www.form-urlencoded)
// 创建实例
const params = new URLSearchParams();
// 添加参数
params.append('key1',value1);
params.append('key2',value2);
// 将params放入请求中并发送请求
axios.post('/api/test',params)
.then(ret=>{
console.log(ret.data)
})
4.PUT请求传参
// JSON形式
axios.put('/adata',{
uname:'tom',
pwd:123
}).then(ret=>{
console.log(ret.data)
})
#响应请求
app.put('/adata',(req.res)=>{
res.send(req.body.uname+'-----'req.body.pwd)
}
// 表单形式->创建实例
const params = new URLSearchParams();
// 添加参数
params.append('key1',value1);
params.append('key2',value2);
// 将params放入请求中并发送请求
axios.put('/api/test',params)
.then(ret=>{
console.log(ret.data)
})
axios拦截器
请求拦截器
axios->请求拦截器->客户端
axios.interceptors.request.use(function(config){
console.log(config.url)
config.headers.mytoken = 'myToken';
// 需要return出去,不然拦截器配置失效
return config
},
function(err){
console.log(err)
})
axios.get('url')
.then(function(data){
console.log(data)
})
响应拦截器
在获取数据之前对数据做一些加工处理
服务器->响应拦截器->axios
axios.interceptors.response.use(function(res){
console.log(res)
// 这里直接拿到了data数据
var data = res.data;
// 返回给axios
return data
},
function(err){
console.log(err)
})
axios.get('url')
.then(function(data){
// 打印出来的是后台传递的数据
console.log(data)
})
async
- asunc/await 是ES7引入的新语,可以更加方便的进行异步操作
- async 关键字用于函数上(async函数的返回值是Promise实例对象)
- await 关键字用于async函数当中(await可以得到异步的结果)
// 返回值promise对象
async function querData(id){
const ret = await axios.get('/data');
return ret;
}
querData().then(function(data){
console.log(data)
})
aysnc/await处理多个异步请求
aysnc function queryData(){
var info = await axios.get('async1');
var ret = await axios.get('async2?info'+info.data)
return ret.data
}
quertData().then(function(data){
console.log(data)
})
Router路由
1.后端路由
- 概念:根据不同的用户URL请求,返回不同的内容
- 本质:URL 请求地址与服务器资源之间的对应关系
2.前端路由
- 概念:根据不同的用户事件,显示不同的页面内容
- 本质:用户事件与事件处理函数之间的对对那个欢喜
Vue Router 包含功能
- 支持HTML5历史模式或hash模式
- 支持嵌套路由
- 支持路由参数
- 支持编程式路由
- 支持命名理由
使用步骤:
// router-link是 vue 中提供的标签,默认会被渲染为a标签
// to 属性默认会被渲染为 href 属性
// to 属性的值会被默认渲染为 # 开头的 hash地址
// 1. 创建路由
<router-link to = '/register'>Register</router-link>
<router-link to = '/user'>User</router-link>
// 2.添加路由占位符
<router-view></router-view>
// 3.定义路由组件
const User = {
template:'User组件
'
}
const Register = {
template:'Register
'
}
// 4. 配置路由规则并创建路由实例
var router = new VueRouter({
// routes 是路由规则数组
routes:[
// 每个路由规则都是一个配置对象,其中至少包含path 和component两个属性
// path:表示当前路由规则匹配的 hash 地址
// component:表示当前路由规则对应要展示的组件
{path:'/user',component:User},
{path:'/register',conponent:Register}
]
})
// 5.把路由挂载到Vue根实例中
const vm = new Vue({
el:'#app',
data:{},
// 挂载路由实例对象
// 在ES6 中属性名跟变量相同可以直接写上变量值
// router:router
router
router
})
路由重定向
用户在访问地址 A 的时候,强制用户跳转到 地址 c,从而展示特定的组件页面。
通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便的设置路由的重定向
var router = new VueRouter({
routes:[
// 其中,path 表示需要被重定向的 原地址,redirect 表示被重定向到哪里
{path:'/',redirect:'/user'},
{path:'/user',component:User},
{path:'/register',conponent:Register}
]
})
路由嵌套
- 点击父级路由链接显示模板内容
- 模板内容中又有子级路由链接
- 点击子级路由链接显示子级模板内容[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XFEXc8k8-1596001043681)(/Users/limboaaa/Library/Application Support/typora-user-images/截屏2020-07-28 上午10.55.46.png)]
const Register = {
template:
`
register
// 子组件路由
tab1
tab2
// 子组件路由占位符
`
}
const router = new VueRouter({
routes:[
{path:'/',redirect:'/user'},
{path:'/user',component:User},
// 构建关系
{path:'/register',
component:Register,
// children[]子规则
children:[
{path:'/register/tab1',component:Tab1},
{path:'/register/tab2',component:Tab2}
]
},
]
})
路由动态匹配
基本用法
$route与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
var router = new VueRouter({
routes:[
// 动态路径参数,以冒号开头
{path:'/user/:id',component:User}
]
})
const User = {
template:
'
<div>
// 路由组件中通过$route.params获取路由参数
User{{$route.params.id}}
</div>
'
}
props的值为布尔类型
const router = new VueRouter({
routes:[
//如果 props 被设置为 true ,route.params 将会被设置为组件属性
{path:'/user/:id',component:User,props:true}
]
})
const User = {
props:['id'], //使用props接受路由参数
template:
'
// 使用路由参数
<div>{{id}}</div>
'
}
# 接受一个对象时
const router = new VueRouter({
routes:[
//如果 props 被设置为 true ,route.params 将会被设置为组件属性
{path:'/user/:id',component:User,props:{uname:'jack',age:23}}
]
})
const User = {
// 此时再想去接受id 已经不能访问了,因为props 已经是一个对象了,Props中有什么,才能取什么!
props:['uname','age'], //使用props接受路由参数
template:
'
// 使用路由参数
<div>{{id}}</div>
'
}
# 接受一个对象,并拿到id
const router = new VueRouter({
routes:[
//如果 props 被设置为 true ,route.params 将会被设置为组件属性
{path:'/user/:id',
component:User,
// roite->动态参数对象
props:route => ({uname:'jack',age:20,id:route.params.id})}
}
]
})
const User = {
props:['uname','age','id'], //使用props接受路由参数
template:
'
// 使用路由参数
<div>{{id+'-'+uname+'-'+age}}</div>
'
}
路由命名
为了更加方便的表示路由的路径,可以给路径规则起个别名
// name:路由别名 params:需要的参数
<router-link :to="{name :'user',params:{id:3}}"></router-link>
const router = new VueRouter({
routes:[
{
// 该路由别名
name:'user',
path:'/user/:id',
component:User
}
]
})
页面导航的两种方式
- 声明式导航:通过点击链接实现导航的方式
- 链接 或vue中的
- 编程式导航:通过调用JavaScript形式的API实现导航的方式,叫做编程式导航
- 例如:普通网页中的location.href
编程式导航基本用法
- this.$router.push(‘hash地址’)
- this.$router.go(n) // 历史记录的前进或后退
// 定义路由组件
const User = {
template:
`
`,
methods: {
goRegister:function(){
// 完成导航功能
this.$router.push('/register')
}
},
}
const Register = {
template:
`
register
`,
methods: {
goBack:function(){
this.$router.go(-1)
}
},
}
后台管理实例
<script>
// 定义 APP 根组件
const App = {
template: `
传智后台管理系统
用户管理
权限管理
商品管理
订单管理
系统设置
`
}
const Users = {
data() {
return {
userlist: [
{ id: 1, name: '张三', age: 10 },
{ id: 2, name: '李四', age: 20 },
{ id: 3, name: '王五', age: 30 },
{ id: 4, name: '赵六', age: 40 }
]
}
},
methods: {
goDetail(id) {
console.log(id)
this.$router.push('/userinfo/' + id)
}
},
template: `
用户管理区域
编号 姓名 年龄 操作
{{item.id}}
{{item.name}}
{{item.age}}
详情
`
}
const UserInfo = {
props: ['id'],
template: `
用户详情页 --- 用户Id为:{{id}}
`,
methods: {
goback() {
// 实现后退功能
this.$router.go(-1)
}
}
}
const Rights = {
template: `
权限管理区域
`
}
const Goods = {
template: `
商品管理区域
`
}
const Orders = {
template: `
订单管理区域
`
}
const Settings = {
template: `
系统设置区域
`
}
// 创建路由对象
const router = new VueRouter({
routes: [
{
path: '/',
component: App,
redirect: '/users',
children: [
{ path: '/users', component: Users },
{ path: '/userinfo/:id', component: UserInfo, props: true },
{ path: '/rights', component: Rights },
{ path: '/goods', component: Goods },
{ path: '/orders', component: Orders },
{ path: '/settings', component: Settings }
]
}
]
})
const vm = new Vue({
el: '#app',
router
})
</script>
前端工程化
模块化相关规范
- 模块化,就是把单独的一个功能封装到一个模块(文件中),模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块
- 模块化开发的好处:方便代码复用,提高开发效率,便于维护
服务器端模块化规范
CommonJS
- 模块分为 单文件模块 与 包
- 模块成员导出: module.exports 和exports
- 模块成员导入:require(‘模块标识符’)
ES6模块化规范
ES6模块化规范,是浏览器端与服务器端通用的模块化开发规范。
- 每个 js 文件都是一个独立的模块
- 导入模块成员使用 import 关键字
- 暴露模块成员使用 export 关键字
默认导出
- 默认导出语法 export default 默认导出的成员
- 在每个模块中只能使用一次export default 否则将会报错
// 当前文件模块为 m1.js
let a = 10;
let c = 20;
let d = 30
function show();
// 将本模块中的私有成员暴露出去,供其他模块使用
export default{
a,
c,
show
}
默认导入
- 默认导入语法 import 接受名称 from ‘模块标识符’
// 导入模块成员
import m1 form './m1.js'
console.log(m1)
// 打印输出结果为:
{a:10,c:20,show:[function:show]}
按需导出
- 按需导出语法 export let s1 = 10
// 按需导出
export let r = 10;
export let g = 20;
export function say(){
console.log(sayFunction)
};
按需导入
- 按需导入语法 import {s1} from ‘模块标识符’
// 如果想按需导出跟默认导出同时出现 需要使用',{}' 可以使用as 给该属性起别名
import m1,{r,g as gg,say}from './m1.js'
// console.log(m1)
console.log(say)
直接导入并执行模块代码
有时候,我们只想单纯执行某个模块中的代码,并不需要得到模块中向外暴露的成员,
此时,可以直接导入并执行模块代码。
// m2模板中的内容
for(let i = 0;i<3;i++){
console.log(i)
}
// index.js 中导入
import './m2.js'
//控制台输出结果
1
2
3
webpack
概述:
一个流行的前端项目构建工具(打包工具),webpack提供了友好的模块化支持,以及代码压缩混淆,处理js兼容问题、性能优化等强大功能,提高开发效率和项目的可维护性。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-506vQ6LR-1596001043683)(/Users/limboaaa/Library/Application Support/typora-user-images/截屏2020-07-28 下午8.58.14.png)]
使用
->创建列表隔行变色项目
- 新建项目空白目录,并运行 npm init -y 命令,初始化包管理配置文件 package.json
- 新建 src 源代码目录
- 新建 src -> index.html 首页
- 初始化首页基本的结构
- 运行 npm install jquery -s 命令,安装jQuery
- 通过模块化的形式,实现列表隔行变色效果
此处有ES6兼容性问题,需要配合webpack使用。
- 在项目根目录中,创建名为webpack.config.js 的webpack配置文件
1.webpack配置文件:
module.exports = {
mode:'development' // mode 用来指定构建模式,development该值为开发模式,代码不会混淆、压缩
}
2.在package.json 配置文件中的scripts节点下,新增dev 脚本如下
"scripts":{
"dev":"webpack" // script 节点下的脚本,可以通过npm run执行
}
3.在终端中运行 npm run dev 命令,启动 webpack 进行项目打包。
配置打包的入口与出口
- 打包的入口文件为 scr -> index.js
- 打包的输出文件问 dist -> main.js
如果需要修改打包的入口与出口,可以在 webpack.config.js 中新增如下配置信息:
const path = require('path') // 导入 node.js中专门操作路径模块
module.exports = {
entry:path.join(_dirname,'./src/index.js'), // 打包入口文件位置
output:{
path:path.join(_dirname,'./dist'),// 输出文件的存放路径
filename:'bundle.js' // 输出文件的名称
}
}
配置自动webpack打包功能
- 运行 npm install webpack-dev-server -D命令,安装支持项目自动打包的工具
- 修改 package.json ->scripts 节点中的dev命令如下
"scripts":{
"dev":"webpack-dev-server" // script 节点下的脚本,可以通过 npm run dev执行
}
- 将 src -> index.html 中,script 脚本的引用路径,修改为’bundle.js’
- 运行 npm run dev 命令重新打包
- 访问 http://localhost:8080 查看自动打包效果
- 在文件夹中生成的bundle.js 文件运行在内存中
- 注意:
- webpack-dev-server 会启动一个实时打包的 http 服务器
- webpack-dev-server 打包生成的输出文件,默认放到项目根目录中,并隐藏。
配置生成预览页面
- npm install html-webpack-plugin -D 下载插件
- 修改 webpack.config.js 文件头部区域,添加如下配置:
// 导入生成预览页面的插件,得到一个 构造函数
const HtmlWebpackPlugin = require('html-web-plugin');
const htmlPlugin = new HtmlWebpackPlugin({
template:'./src/index.html',//指定要用到的模板文件
filename:'index.html' // 指定生成的文件的名称,该文件存在于内存中,在项目目录中不现实
})
- 修改webpack.config.js文件中对外暴露的配置对象,新增如下配置节点
module.exports = {
plugins:[htmlPlugin]// plugins 数组是 webpack 打包期间会用到的一些插件列表
}
打包完成自动打开项目
配置参数
//package.json 中配置
// --open 打包完成自动打开浏览器页面
// --host 配置 Ip 地址
// --port 配置端口
"scripts":{
"dev":"webpack-dev-server --open --host 127.0.0.1 --port 8088"
}
通过loader 打包非js模块
在实际开过程中,webpack 默认只能打包处理以 .js 后缀名的模块,其他非 .js 后缀名结尾的模块,webpack默认处理不了,需要调用 loader 加载器才可以正常打包,否则会报错。
loader 加载器可以协助 webpack 打包处理特定的文件模块,比如:
- less-loader 可以打包处理 .less 相关的文件
- sass-loader 可以打包处理 .scss 相关的文件
- url-loader 可以打包处理 css 中与 url路径相关的文件[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDNB1R4C-1596001043684)(/Users/limboaaa/Library/Application Support/typora-user-images/截屏2020-07-29 上午10.41.54.png)]
打包处理css文件
- npm i style-loader css-loader -D 安装处理css文件的 loader
- 在 webpack.config.js 的 module ->rules 数组中,添加 loader规则如下
# webpack.config.js
// 所有第三方文件模块的匹配规则
module:{
rules:[
{test:/\.css$/,use:['style-loader','css-loader']}
]
}
# test 表示匹配的文件配型, true 表示对应要调用的loader
# use 数组中指定的 loader 顺序是固定的
# 多个 loader 的调用顺序是:从后往前调用
打包处理less 文件
- npm i less-loader less -D 安装处理 less 文件的 loader
- 在 webpack.config.js 的 module ->rules 数组中,添加 loader规则如下
# webpack.config.js
// 所有第三方文件模块的匹配规则
module:{
rules:[
{test:/\.less/,use:['style-loader','css-loader','less-loader']}
]
}
打包处理scss 文件
- npm i sass-loader node-sass -D 安装处理 sass 文件的 loader
- 在 webpack.config.js 的 module ->rules 数组中,添加 loader规则如下
# webpack.config.js
// 所有第三方文件模块的匹配规则
module:{
rules:[
{test:/\.scss/,use:['style-loader','css-loader','sass-loader']}
]
}
配置postCSS 自动添加css的兼容前缀
- 运行 npm i postcss-loader autoprefixer -D命令
- 在项目根目录中创建 postcss 的配置文件 postcss.config.js并初始化如下配置
const autoprefixer = require('autoprefixer') // 导入自动添加前缀插件
module.exports = {
plugins:[autoprefixer] //挂载插件
}
3.在 webpack.config.js 的 module->rules 数组中,修改 css 的loader规则如下
module:{
rules:[
{test:/\.css$/,use:['style-loader','css-loader','postcss-loader']}
]
}
打包处理图片 文件字体文件
- npm i url-loader file-loader -D
- 在 webpack.config.js 的 module ->rules 数组中,添加 loader规则如下
module:{
rules:[
{test:/\.jpg|png|git|bmp|ttf|eot|svg|woff|woff2$/,
use:'url-loader?limit=16940' // 图片大小 单位字节(byte)
}
]
}
打包处理js文件的高级语法
- 安装babel 转换器相关的包:npm i babel-loader @babel/core @babel/runtime -D
- 安装babel 语法插件相关的包:npm i @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
- 在项目跟目录中,创建babel配置文件babel.config.js 并初始化如下配置:
module.exports = {
presets:['@babel/preset-env'],
plugins:['@babel/plugin-transform-runtime','@babel/plugin-proposal-class-properties'] //挂载插件
}
4.在 webpack.config.js 的module -> rules 数组中,添加 loader 规则如下:
// exclude 为排除项 表示babel-loader 不需要处理:node_modules中的js文件
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
Vue 单文件组件
传统组件的问题和解决方案
- 全局定义的组件必须保证组件的名称不重复
- 字符串模板缺乏语法高亮
- 不支持CSS意味着当HTML和JavaScript 组件化时,CSS明显会被遗漏。
- 没有构建步骤限制,只能使用HTML和ES5 JavaScript,而不能使用预处理器(如:babel)