小型项目 就可使用 vue 就高度了 随着页面的复杂程序提升,就要学习 vue-rouer 来管理更多的页面 再随着项目的数据愈来愈多,管理数据也变得麻烦起来了,就开始使用 vuex 来管理数据javascript
3.2 框架 : 一整套的解决方案php
好比 : 想要添加样式, 就调用 jquery 中的 .css() / .addClass()css
好比 : 想给 A:设置样式 A.css(), B:addClass() C:style.background='red'
html
####2. 框架 (Framework), 表明:vue前端
好比 : 想用vue,组件里遍历就得使用 v-for, 下次不用 v-for 了,使用 for 不行 v-for='item in list'vue
也就是 : 谁起到了主导做用java
Vue 使用的是 MVVM 模式node
频繁的操做DOM
数据双向绑定
让数据自动的双向同步
每一个人操做 DOM 的方法不同,会形成性能不同 官网 : 虽然没有彻底遵循 MVVM 模型,可是 Vue 的设计也受到了它的启发。所以在文档中常常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。jquery
npm i vue
(小写)<script src='./vue.js'></script>
const vm = new Vue({
// 指定 vue 管理的边界
el: '#app',
// 提供视图中 须要的数据
// 视图能够直接使用data中的数据
data: {
msg: 'xxx'
}
})
复制代码
{{}}
从data
中获取数据,并展现在模板中{{}}
中只能出现 js 表达式1 'abc' false [] {}
1+2 arr.join('-') true ? 123 : 321
if语句 for语句
v-model 指令 : 数据双向绑定的指令
做用 : 把data中的msg值 和 input上的值 绑定到一块儿
注意 : v-model只能用在 表单控件上 (input checkbox 等)
> 能够在浏览器分别演示 V => M 和 M =>V
复制代码
let obj = {}
let temp
obj.name = 'zhanhgsan'
// 参数1 : 要给哪一个对象设置属性
// 参数2 : 给对象设置什么属性
// 参数3 : 属性的修饰符
Object.defineProperty(obj, 'name', {
set: function(newVal) {
console.log('赋值了', newVal)
},
get: function() {
console.log('取值了')
return temp
}
})
复制代码
<input type="text" id="txt" />
//1. 拿到文本框
const txt = document.getElementById('txt')
//2. 时刻监听txt ,拿到最新的值
txt.oninput = function() {
console.log(this.value)
obj.name = this.value
}
//3. 数据模型
var obj = {}
let temp
Object.defineProperty(obj, 'name', {
// 给属性赋值的时候会掉
set: function(newVal) {
console.log('调用了set', newVal)
temp = newVal
txt.value = newVal
},
get: function() {
console.log('调用了get')
return temp
}
})
复制代码
//1. 获取 input的值,最新值
//2. 经过监听oninput 拿到最新值
//3. 把最新值赋值给 obj.name
//4. 就会掉了set方法,就会修改了数据
复制代码
//1. obj.name = 'xxx'
//2. 调用 set方法
//3. 把值赋值给input元素
复制代码
说明 : 用在
表单
元素中, 用来实现数据双向绑定
(input checkbox 等等) 做用 : 将数据txt
和文本框的值
绑定到一块儿, 任何一方发生改变,都会引发对方的改变 注意 : v-model 在不一样类型的表单元素中,该指令的做用不一样webpack
<!-- 文本输入框 绑定的是值 -->
<input type="text" v-model="txt" />
<!-- 多选框、按钮 绑定的选中状态 -->
<input type="checkbox" v-model="isChecked" />
复制代码
说明 : 设置文本内容
msg1: '<a>这是一条信息</a>',
msg2: '<a href="#">我也是一条信息</a>'
复制代码
说明 : 动态绑定数据 (单向) 出现缘由 : 在 HTML 属性中, 没法使用插值表达式 步骤:
// 加载静态数据
<a href="https://wbaidu.com">aaa</a>
// 想加载动态数据 {{ }}能够获取data中的数据
// 可是 {{}} 不能使用在属性中
<a href="{{ src }}">aaa</a>
// 因此使用v-bind
<a v-bind:href="{{ src }}">aaa</a> ok
<img v-bind:src="src"> ok
复制代码
缩略 : v-bind 所有省略 只留下一个
:
改成 :
<a :href="src">aaa</a> ok
<img :src="src" /> ok
复制代码
之后 使用 静态加载数据 :
<a href="https://wbaidu.com">aaa</a>
动态加载数据 :<a :href="href">aaa</a>
// v-model : 数据双向绑定 表单元素上
// : : 动态绑定数据(单向) 任意元素动态读取属性
容易出错点 :
<!-- v-model 数据双向绑定 -->
<!--场景 : 表单元素中 -->
<input type="checkbox" v-model="isChecked1" /> <br />
<!-- v-bind 数据动态绑定 (单向) -->
<!--场景 : 主要用在属性中 -->
<input type="checkbox" :checked="isChecked2" />*
复制代码
1.操做样式
<!-- 1. 静态类名 -->
<h1 class="red">哈哈</h1>
<!-- 2. 动态类名 -->
<h1 :class="cls">哈哈</h1>
<!-- 3. 最经常使用 -->
<!-- :class 里的值是一个对象 键 : 类名 (可能会要,也能够不要) 值 : 布尔值, true/false 肯定类要不要 -->
<h1 :class="{ red:isRed , fz:isFZ}">哈哈</h1>
<!-- 4. style -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>
复制代码
2.其余操做
<!-- 1 -->
<!-- 重点 -->
<div :class="{ active: true }"></div>
===>
<div class="active"></div>
<!-- 2 -->
<div :class="['active', 'text-danger']"></div>
===>
<div class="active text-danger"></div>
<!-- 3 -->
<div :class="[{ active: true }, errorClass]"></div>
===>
<div class="active text-danger"></div>
--- style ---
<!-- 1 -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>
<!-- fz : 80 -->
<!-- 2 将多个 样式对象 应用到一个元素上-->
<!-- baseStyles 和 overridingStyles 都是对象 -->
<!-- 若是有相同的样式,之后面的样式为准 -->
<div :style="[baseStyles, overridingStyles]"></div>
复制代码
注册事件/绑定事件
v-on:click 绑定了一个单击事件
: 后面是事件名称
<button v-on:click="fn">按钮</button>
复制代码
缩写 : @click='fn' <button @click='fn'>按钮</button>
函数写在 methods
里面
fn : function(){ ... }
fn() { ... }
复制代码
> 在函数里面操做数据
- 获取数据 this.msg
- 修改数据 this.msg = 'XXX'
复制代码
@click='fn(123)'
复制代码
5.2 事件对象 $event
<!-- 4.1 绑定事件对象的时候, 没有添加小括号,此时,直接在方法中,经过参数 e 就能够获取到事件对象 -->
<!-- 4.2 若是添加小括号,就拿不到事件对象了,vue留了一个$event -->
<button @click="fn1($event,123)">我是按钮</button>
复制代码
<!-- 需求1 : 最经常使用 遍历数组 -->
<!-- 做用 : 遍历 list1 数据, 为数据中的每一项生成一个li标签 -->
<!-- item 数组里的每一项元素 -->
<ul>
<li v-for="(item,index) in list1">{{ item }} - {{ index }}</li>
</ul>
<!-- 需求2 : 遍历元素是对象的数组 -->
<ul>
<li v-for="item in list2">{{ item.name }} - id:{{ item.id }}</li>
</ul>
<!-- 需求3 : 遍历对象 -->
<ul>
<li v-for="(item,key) in obj">{{ item }}-{{key}}</li>
</ul>
<!-- 需求4 : 想要生成10个h1 -->
<h1 v-for="item in 10">我是h1 {{ item }}</h1>
复制代码
重点是遍历数组,,其余的了解便可
注意用v-for更新已经渲染过的元素列表的时候,他会默认就地复用策略,若是数组的顺序发生改变,vue不会必定dom元素来匹配顺序,而是简单的复用此处的每一个元素,这样每一个节点的状态就会对应不上
解决这时候就须要给每一个列表元素提供一个key
,这个key
须要是惟一的,以保证vue能准确的追踪到每一个节点,key
最好是列表中每项的id
###一 : 准备工做
演示效果 :
当前任务:敲代码、视频、游戏
git clone https://github.com/tastejs/todomvc-app-template.git
安装依赖包 : npm i
安装 vue : npm i vue
导入 vue : <script src="./node_modules//vue/dist/vue.js"></script>
在
index.html
里的app.js
导入以前导入,由于 app.js 里 就要用到 vue 了
实例化 vue :在app.js
中建立 vue 示例,并设置好边界 el:'#app'
找到 index.html ,给 section 标签添加一个 id
测试 vue :
data 中随便来一个 msg 看能不能显示到视图中
这里先甩一张图

#####注意 :
生命周期钩子函数
, 咱们只须要提供这些钩子函数便可说明 : 在实例初始化以前,数据观测 和 event/watcher 事件配置以前被调用
组件实例刚被建立,组件属性计算以前, 例如 data 属性 methods 属性
注意 : 此时,没法获取 data 中的数据 和 methoids 中的方法
场景 : 几乎不用
说明 : 组件实例建立完成,属性已绑定, 能够调用 methods 中的方法、能够获取 data 值
使用场景 : 1-发送 ajax 2-本地存储获取数据
beforeCreate() {
// 没法获取数据和事件
console.warn('beforeCreate', this.msg, this.fn)
},
created() {
console.warn('created', this.msg, this.fn)
},
复制代码
vm.$mount(el)
去指定边界vm.$mount('#app')
复制代码
template
option?// 若是提供了 template, 那么 vue 就会将 template 的内容进行编译,编译后,替换页面中 vue 管理的边界
template : ` <h1>嘻嘻</h1> `,
复制代码
说明 : 挂载以后, DOM 完成渲染
使用场景 : 1-发送 ajax 2-操做 DOM
记得把template去掉
// 渲染DOM以前
beforeMount() {
// 渲染以前的 <h1 id="h1" @click="fn">{{ msg }}</h1>
console.log(document.getElementById('h1'))
},
// 渲染DOM以后 <h1 id="h1">测试</h1>
mounted() {
console.log(document.getElementById('h1'))
}
复制代码
说明:数据更新时调用,发生在虚拟 DOM 从新渲染和打补丁以前。你能够在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
注意:此处获取的数据是更新后的数据,可是获取页面中的 DOM 元素是更新以前的
小提示 : 打印 this.$el ,打开小三角是以后的,是由于打印是有监听的功能,展现的是后面更改以后的
说明:组件 DOM 已经更新,因此你如今能够执行依赖于 DOM 的操做。
beforeUpdate() {
// 更新以前的值 : 信息
console.warn('beforeUpdate', document.getElementById('h1').innerText)
},
updated() {
// 更新以后的值 : 信息1111
console.warn('updated', document.getElementById('h1').innerText)
}
复制代码
created() {
this.timerId = setInterval(() => {
console.log(1111);
}, 500);
},
// 若是当组件销毁了,还不清除定时器会出现性能问题
// 在浏览器中能够尝试销毁 vm.$destroy()
// 最后销毁
beforeDestroy() {
clearInterval(this.timerId)
},
复制代码
说明:Vue 实例销毁后调用。调用后,Vue 实例指示的全部东西都会解绑定,全部的事件监听器会被移除,全部的子实例也会被销毁。
created {
this.list = localStorage.getItem('list')
}
复制代码
json-server 做用 : 根据指定的 JSON 文件, 提供假数据接口
地址 : json-server
使用步骤
1. 全局安装 json-server : `npm i -g json-server`
2. 准备一个json数据
3. 执行 : `json-server data.json`
> json数据参考
json数据能够参考 :
{
"todos": [
{
"id": 1,
"name": "吃饭",
"age": 20
}
]
}
复制代码
REST API 格式
* 1. 查询 : GET
* 2. 添加 : POST
* 3. 删除 : DELETE
* 4. 更新 : PUT 或者 PATCH(打补丁)
复制代码
* 1. 查询所有数据 http://localhost:3000/todos
* 查询指定数据 http://localhost:3000/todos/2
*
* 2. 添加一个对象 //localhost:3000/todos
* POST
* id 会自动帮咱们添加
*
* 3. 更新数据 http://localhost:3000/todos/3
* PUT 或者 PATCH
* PUT 须要提供该对象的全部数据
* PATCH 只须要提供要修改的数据便可
*
* 4. 删除数据
* http://localhost:3000/todos/3
* DELETE
复制代码
postman
测试接口;读音 : /艾克笑丝/
做用 : 一个专门用来发送 ajax 请求的库, 能够在浏览器或者 node.js 中使用
Promise based HTTP client for the browser and node.js
以Promise为基础的HTTP客户端,适用于:浏览器和node.js
封装ajax,用来发送请求,异步获取数据
复制代码
使用步骤
1. 本地安装 axios : `npm i axios`
2. 导入 axios
3. 使用
复制代码
GTE 方式发送请求
// 方式1
axios.get('http://localhost:3000/todos/3').then(res => {
console.log('获取到数据了:', res.data)
})
// 方式2
axios
.get('http://localhost:3000/menus', {
params: {
id: 003
}
})
.then(res => {
console.log('获取到数据了:', res.data)
})
复制代码
五、 POST 方式发送请求
// post 请求
axios
// 第一个参数:表示接口地址
// 第二个参数:表示接口须要的参数
.post('http://localhost:3000/todos', {
name: 'axios添加数据',
done: true
}).then ( res => 打印 res)
复制代码
使用axios测试 todos 的几种接口
//1. GET
// 没有参数
axios.get('http://localhost:3000/todo').then(res => {
console.log(res)
})
// 有参数
axios.get('http://localhost:3000/todo/1').then(res => {
console.log(res)
})
axios
.get('http://localhost:3000/todo', {
params: {
id: 2
}
})
.then(res => {
console.log(res)
})
// 2. POST
axios
.post('http://localhost:3000/todo', {
name: 'XXX',
age: 1
})
.then(res => {
console.log(res)
})
//3. 删除
axios.delete('http://localhost:3000/todo/8', {}).then(res => {
console.log(res)
})
//4. 更新 - put
axios
.put('http://localhost:3000/todo/2', {
name: '111',
age: 300
})
.then(res => {
console.log(res)
})
// 4. 更新 - patch
axios
.patch('http://localhost:3000/todo/1', {
age: 3000
})
.then(res => {
console.log(res)
})
复制代码
获取所有
axios.get('http://localhost:3000/list').then(res => {
console.log(res.data);
this.list = res.data;
});
复制代码
删除任务
axios.delete('http://localhost:3000/list/' + id).then(res => {
this.list = this.list.filter(item => item.id !== id);
console.log(res);
});
复制代码
添加任务
# id 会自动加
axios
.post('http://localhost:3000/list', {
name: todoName,
done: false
})
.then(res => {
console.log(res.data);
this.list.push({
// 属性名 和属性值 同样的话,,能够省略一个
id,
name: todoName,
done: false
});
});
复制代码
更新任务 (在 hideEdit 里实现)
# 难点1 : 在 hideEdit 这个方法里
# 难点2 : 获取的这个id 就是editId
hideEdit(e) {
axios.patch('http://localhost:3000/list/' + this.editId, {
name: e.target.value
}).then(res => {
console.log(res);
this.editId = -1;
})
},
复制代码
删除已经完成 的
# 由于 这个假接口没有实现如下删除 完毕
clearCompleted() {
// 清除已经完成的,,只须要过滤出来未完成的便可
let arr = this.list.filter(item => item.done);
arr = arr.map(item => item.id);
for (let i = 0; i < arr.length; i++) {
axios.delete('http://localhost:3000/list/' + arr[i]).then(res => {
this.list = this.list.filter(item => item.id != arr[i]);
});
}
},
复制代码
点击修改状态
# 单独给 checkbox 都注册点击事件
clickBox(id) {
let todo = this.list.find(item => item.id == id);
axios.patch('http://localhost:3000/list/' + id, {
done: !todo.done
}).then(res => {
console.log(res);
});
}
复制代码
单页web应用,
就是只有一个web页面的应用,
是加载单个HTML页面,
并在用户与应用程序交互时动态更新该页面的web应用程序
复制代码
对于传统的多页面应用程序来讲, 每次请求服务器返回的都是一个完整的页面
对于单页应用程序来讲,
只有第一次会加载页面,
之后的每次请求,
仅仅是获取必要的数据.而后,
由页面中js解析获取的数据,
展现在页面中
复制代码
Vue 中的两种注册组件的方法 1.全局注册 2.局部注册
全局组件在全部的vue实例中均可以使用
局部组件在全部的当前实例中可使用
复制代码
/** * 第一个参数 : 组件名 * 第二个参数 : 是一个配置对象, 该配置对象与 Vue 实例的配置对象几乎彻底相同 * 也就是说: vue实例中用到的配置项,和组件中的配置项几乎相同 */
Vue.component('hello', {
template: ` <h1 class="red">这是hello组件</h1> `
})
复制代码
var Component = function() {}
// 使用对象
Component.prototype.data = {
demo: 123
}
// 使用函数
Component.prototype.data = function() {
return {
demo: 111
}
}
var component1 = new Component()
var component2 = new Component()
component1.data().demo = '8888'
console.log(component2.data().demo) // 456
复制代码
示例:
<h1 @click='fn' class="red">这是hello组件</h1>
methods: {
fn() {
console.log('fn')
}
},
computed: {},
watch: {},
filters: {}
}
复制代码
todo-head.js
<script src="./components/todo-head.js"></script>
<todo-head></todo-head>
<child :msg="pmsg"></child>
复制代码
props: ['msg']
复制代码
完善 TodoMVC => 完成 传值 + 渲染列表页
1 父组件中提供一个方法
pfn(arg) {
console.log('父组件中接受到子组件传递过来的数据:', arg)
}
复制代码
2 将这个方法传递给子组件
// 自定义事件 <child @fn="pfn"></child>
复制代码
3 子组件调用这个方法( 触发父组件中传递过来的自定义事件 )
// 这个方法是点击事件触发的
handleClick() {
// 调用父组件中的方法 fn
// 注意:经过 $emit 方法来触发事件 fn
// 第一个参数:表示要触发的自定义事件名称,也就是 @fn
// 第二个参数:表示要传递给父组件的数据
this.$emit('fn', 'child msg')
}
复制代码
完善 TodoMVC => 完成 传值 +添加+ 删除+清除完成
全部的 prop 都使得其父子 prop 之间造成了一个
单向下行绑定
:父级 prop 的更新会向下流动到子组件中,可是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而致使你的应用的数据流向难以理解。 看图 当 todo-head 中的 todoName 设置数据后回车添加到 todoList,todoList 的长度就会发生变化, 而后就会根据(组件与组件之间的)单向数据流,把数据单向下流到子组件中 并且必须是经过 props 往下传递的才能够
验证 props 只读
正常下是不须要子组件修改父组件传过来的值的,可是.....
修改父组件传给子组件的
数据
思路 : 把接收过来的数据,保存到 data 中一个临时值
Vue.component('child', {
template: ` <div>子组件 {{ cmsg }} </div> `,
data() {
return {
cmsg: this.msg
}
},
props: ['msg'],
created() {
this.cmsg = 666
}
})
复制代码
官 : HTML 中的特性名是大小写不敏感的,因此浏览器会把全部大写字符解释为小写字符。
html 的标签和 属性 都是同样,忽略大小写
<H1 TITLE="哈哈">我是h1</H1>
官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名很差使了
<child :cMsg="pmsg"></child>
会报警告,父传子也接收不到了You should probably use "c-msg" instead of "cMsg".
方式 1 : 全用小写,不要使用驼峰命名
接收 :
cmsg
props/读取 :cmsg
方式 2 官 : 须要使用其等价的 kebab-case (短横线分隔命名) 命名:
接收 :
:c-msg='pmsg'
props/读取 :cMsg
计算属性 : 已知值(todoList 在 根组件) ==> 获得一个新值(子组件里使用)
父 => 子通信
需求 : 组件 jack ===> 恁弄啥哩 ===> 组件 rose
事件总线 (event bus 公交车) 的机制
来实现的空Vue实例
// 第一步 : 事件总线
var bus = new Vue()
// 第二步 : 发送数据 可在点击事件里 触发事件
// 参数1 : 惟一标识 参数2:参数
bus.$emit('todo', '恁弄啥哩?')
// 第三步 : 接收数据 可在 created 里 注册事件
bus.$on('todo', arg => {
console.log('接收过来的', arg)
})
复制代码
// 注册局部组件:
components: {
// child表示组件名称
// 值为配置对象,与 Vue.component 中的第二个参数相同
// 注意:子组件child属于 Vue实例,所以,只能在 Vue实例的模板中使用
child: {
template: ` <div>这是局部组件 child</div> `
}
}
复制代码
说明 : vm.$refs
一个对象, 持有已注册过 ref 的全部子组件 ( HTML 元素)
使用 :
// 标签
<div ref="div">哈哈</div>
// 组件
<child ref="child"></child>
复制代码
// mounted 操做DOM
* this.$refs.div
* this.$refs.child
复制代码
注意点 : 若是获取的是一个子组件,那么经过 ref 就能获取到子组件中的 data
和 methods
this.$refs.child.num
this.$refs.child.fn
复制代码
场景 : 通常在第三方的组件中, 可能会用到这个功能
示例 :
// 组件
<div ref="div">哈哈</div>
<child ref="child"></child>
// js
mounted() {
console.log(this.$refs.div)
console.log(this.$refs.child.fn)
}
复制代码
单页web应用,
就是只有一个web页面的应用,
是加载单个HTML页面,
并在用户与应用程序交互时动态更新该页面的web应用程序
复制代码
对于传统的多页面应用程序来讲, 每次请求服务器返回的都是一个完整的页面
对于单页应用程序来讲,
只有第一次会加载页面,
之后的每次请求,
仅仅是获取必要的数据.而后,
由页面中js解析获取的数据,
展现在页面中
复制代码
哈希值
( # hash) 与 展现视图内容
之间的对应规则
在 web App 中, 经过一个页面来展现和管理整个应用的功能.
SPA 每每是功能复杂的应用,为了有效管理全部视图内容,前端路由 应运而生. (为何要学习路由??)
简单来讲,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.
当 URL 中的哈希值( `#` hash) 发生改变后,路由会根据制定好的规则, 展现对应的视图内容
复制代码
npm i vue-router
<script src="./vue.js"></script>
// 千万注意 :引入路由必定要在引入vue以后,由于vue-router是基于vue工做的
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
复制代码
3.0 实例路由对象+挂载到 vue 上
const router = new VueRouter() 路由实例 与 Vue 实例 关联到一块儿 验证路由是否挂载成功, 就看打开页面,最后面有没有个
#/
3.1 入口 (#哈希值)
// 方式1 : url地址为入口 调试开发用
输入url地址 改变哈希值
`01-路由的基本使用.html#/one`
// 方式2 : router-link+to
复制代码
// path : 路由路径
// component : 未来要展现的路由组件
routes: [{ path: '/one', component: One }, { path: '/two', component: Two }]
复制代码
3.3 组件
一个哈希值对应一个组件
const One = Vue.component('one', {
template: ` <div> 子组件 one </div> `
})
复制代码
<!-- 出口 组件要展现的地方-->
<router-view></router-view>
复制代码
<!-- 1. 入口 -->
<!-- to 属性 , 实际上就是哈希值,未来要参与路由规则中进行与组件匹配 router-link 组件最终渲染为 : a标签, to属性转化为 a标签的href属性 -->
<router-link to="/one">首页</router-link>
复制代码
组件
组件能够改成对象格式
const One = {
template: ` <div> 子组件 one </div> `
}
复制代码
过程 : 入口 ==> 路由规则 ==> 组件 ==> 出口
演示 : 多个组件匹配
能够有多个入口,但只须要一个出口
示例 :
<div id="app">
<!-- 1 路由入口:连接导航 -->
<router-link to="/one">One</router-link>
<router-link to="/two">Two</router-link>
<!-- 4 路由出口:用来展现匹配路由视图内容 -->
<router-view></router-view>
</div>
<!-- 导入 vue.js -->
<script src="./vue.js"></script>
<!-- 导入 路由文件 -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3 建立两个组件
const One = Vue.component('one', {
template: '<h1>这是 one 组件</h1>'
})
const Two = Vue.component('two', {
template: '<h1>这是 two 组件</h1>'
})
// 0 建立路由对象
const router = new VueRouter({
// 2. 路由规则
routes: [
{ path: '/one', component: One },
{ path: '/two', component: Two }
]
})
const vm = new Vue({
el: '#app',
//0. 不要忘记,将路由与vue实例关联到一块儿!
router
})
</script>
复制代码
<a href="#/one" class="router-link-exact-active router-link-active">One</a>
<a href="#/two" class="">Two</a>
复制代码
.router-link-exact-active,
.router-link-active {
color: red;
font-size: 50px;
}
复制代码
修饰方式 2 : 修改默认高亮类名 (推荐)
由于有时候项目中可能已经针对导航有过设置样式,后来再加的路由,因此若是再从新像方式 1 再加一次,会重复 因此 :能够 修改默认高亮的 a 标签的类名
const router = new VueRouter({
routes: [],
// 修改默认高亮的a标签的类名
// red 是已经存在过的
linkActiveClass: 'red'
})
复制代码
浏览器地址栏中的哈希值 与 router-link 的 to 属性值,彻底匹配对,才会添加该类
浏览器地址栏中的哈希值
包含 router-link 的 to 属性值,就会添加该类名<router-link to="/" exact>
One
</router-link>
复制代码
看图分析: 列表 => 详情组件
<!-- 1. 入口 -->
<router-link to="/detail/1">手机1</router-link>
<router-link to="/detail/2">手机2</router-link>
<router-link to="/detail/3">手机3</router-link>
复制代码
routes: [
// 2 . 路由规则
{ path: '/detail/1', component: Detail },
{ path: '/detail/2', component: Detail },
{ path: '/detail/3', component: Detail }
]
//3. 组件
const Detail = Vue.component('detail', {
template: ` <div> 显示详情页内容....{{ $route.path }} </div> `
})
复制代码
routes: [
// 2 . 路由规则
{ path: '/detail/:id', component: Detail }
]
复制代码
3.2 获取参数的三种正确方式
const Detail = Vue.component('detail', {
template: ` // 方式1 : 组件中直接读取 <div> 显示详情页内容....{{ $route.params.id }} </div> `,
created() {
// 方式2 : js直接读取
// 打印只会打印一次,由于组件是复用的,每次进来钩子函数只会执行一次
console.log(this.$route.params.id)
},
// 方式3 : 监听路由的参数变化 为何不须要深度监听,由于它不是data中的
watch: {
$route(to, from) {
console.log(to.params.id)
}
}
})
复制代码
若是输入的没有带参数的
有参数的对应 : 下面都是正确打开方式
detail/1 ==> 显示详情页内容....1
detail/2 ==> 显示详情页内容....2
detail/3 ==> 显示详情页内容....3
复制代码
若是经过改变 url 地址,不输入参数 就看不到
显示详情页内容
这些字 说明没有正确匹配到detail组件
内
// 可识别的路径是这样的
* detail
* detial/1
* detial/2
* detial/3
复制代码
// 连接:
<router-link to="/user/1001">用户 Jack</router-link>
<router-link to="/user/1002">用户 Rose</router-link>
// 路由:
{ path: '/user/:id', component: User }
// User组件:
const User = {
template: `<div>User {{ $route.params.id }}</div>`
}
复制代码
{ path: '/', redirect: '/home' }
复制代码
概念 ==> webpack 是什么?? 前端模块化打包(构建)工具
webpack能够解决这些依赖关系,并对他们进行打包
1 - 打包 2 - 模块化
语法转换
- Less/SASS 预编译CSS -> CSS -> 浏览器中使用
- ES6 新语法有兼容性问题 -> ES5 -> 浏览器中使用
- const fn = () => {} ===> var fn = function() {}
复制代码
文件压缩、合并
JS/HTML/CSS 压缩后,才能发布上线
文件合并( 无论有多个JS、CSS,默认打包直接生成一个JS文件 )
复制代码
开发期间提供一个服务器环境
自动打开浏览器、监视文件变化,自动刷新浏览器
复制代码
项目上线,打包后才能上线
总结
webpack 这个打包(构建)工具,就是提供了前端开发须要的一整套完整的流程,也就是
webpack 可以渗透的前端开发的各个环节、各个流程中,帮你实现 复杂、繁琐、重复的工做,有了 webpack 后,开发人员只须要关注当前要实现的业务便可。
复制代码
模块化 : 逻辑
组件化 : 界面
webpack为前端提供了模块化开发环境,并且webpack是基于node,有了webpack,就能够像写Node代码同样,写前端代码了
在 webpack 看来全部的资源都是模块,无论是: CSS、图片、字体、JS、html 等
在webpack提供的模块化环境中,
1 想要加载一个JS文件,只须要 require('./a.js')
2 想要加载一个CSS文件,只须要 require('../css/index.css')
3 想要加载一个图片文件,只须要 require('../iamges/a.png')
4 ...
复制代码
入口(entry)、出口(output)、加载器(loader)、插件(plugins)
文件名不能有汉字,不能取名叫 webpack
package.json
, 命令 : npm init -y
npm i -D webpack webpack-cli
webpack : 是 webpack 工具的核心包
webpack-cli : 提供了一些在终端中使用的命令
-D(--save-dev) : 表示项目开发期间的依赖,也就是 : 线上代码中用不到这些包了
复制代码
main.js
文件console.log('我就要被打包了,哦也');
复制代码
package.json
的scripts
中,添加脚本"scripts": {
"build": "webpack main.js"
},
// webpack 是webpack-cli 中提供的命令, 用来实现打包的
// ./main.js 入口文件,要打包哪一个文件
复制代码
npm run build
mode
"build" : "webpack ./main.js --mode development"
// WARNING in configuration
// The 'mode' option has not been set, webpack will fallback to 'production' for this value.
// 若是没有设置 mode 配置项, webpack 会默认提供 开发环境(production)
// Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
// 项目开发的两种环境
1. 开发环境 (development) : 开发过程就是开发环境
2. 生产环境 (production) : 线上环境, 也就是 : 项目作好了,发布上线
生产环境下, 打包生产的js文件都是压缩后的, 开发环境下代码通常是不压缩的
复制代码
src/index.html
html => ul#list>li{我是 li \$}\*10
npm i jquery
, 而且引入 jquery
main.js
, 在 main.js 里写入// 使用ES6的模块化语法
import $ from 'jquery' // 优势 不用沿着路径去找
$('#list > li:odd').css('backgroundColor', 'red')
$('#list > li:even').css('backgroundColor', 'green')
// 语法报错
复制代码
// 引入 main.js 会报错,由于浏览器不支持这个import 的Es6语法
// npm run build 以后
// 引入 dist/main.js 后会ok,由于webpack 帮咱们转化为浏览器可以识别的es5语法了
复制代码
//1. 若是index.html 中引入 jquery , 再引入 mian.js (没有引入jquery了) => ok
//2. 若是index.html 中没有引入 jquery , 直接使用es6的模块化语法 import , 引入main.js就会报错
//3. 若是index.html 中没有引入 jquery , 直接使用es6的模块化语法 import , webapck打包出 dist/main.js 引入 dist/main.js ==> ok
复制代码
为何 dist文件下的main.js
文件里的代码忽然这么多
看图 (打包流程)
code 记得保存一份
准备工做 : src
源文件 : index.html
和main.js
webpack 打包有两种方式
1-命令行 2-配置项
方式 1 : 命令行
* "build" : "webpack ./mian.js" --mode development
* npm run build
* 通常状况下 : 改成
* "build" : 入口 --output 出口
* "build": "webpack ./src/js/main.js --output ./dist/bundle.js --mode development",
*
* 验证 : index.html 引入 bundle.js
复制代码
第一步 : 项目`根目录`下, 建立一个 `webpack.config.js`文件 (文件名固定死)
专门指定其余文件 : --config webpack.XX.js
第二步 : 在 `webpack.config.js` 中,进行配置
// webpack 是基于 node的 , 因此配置文件符合 node 方式书写配置
// 注意 : 不要再这个文件中使用ES6的的模块化 import语法
// main.js里可使用,是由于要经过webpack转化为es5的
// 而这个是webpack 的配置文件,,它是要转化别人的,因此必需要经过
第三步 : 修改 `package.json` 中的 `scripts` , 脚本命令为: "build": "webpack"
第四步 : 执行命令 : `npm run build`
复制代码
const path = require('path')
module.exports = {
// 入口
entry: path.join(__dirname, './src/js/main.js'),
// 出口
output: {
// 出口目录
path: path.join(__dirname, './dist'),
filename: 'bundle.js'
},
// 开发模式
mode: 'development'
}
复制代码
做用 :
1. 可以根据指定的模板文件 (index.html),自动生成一个新的 index.html,而且注入到dist文件夹下
2. 可以自动引入js文件
复制代码
npm i html-webpack-plugin
第一步: 引入模块
const htmlWebpackPlugin = require('html-webpack-plugin')
第二步: 配置
// 插件
plugins: [
// 使用插件 指定模板
new htmlWebpackPlugin({
template: path.join(__dirname, './src/index.html')
})
]
复制代码
做用 : 为使用 webpack 打包提供一个服务器环境
npm i -D webpack-dev-server
"dev" : "webpack-dev-server"
npm run dev
--open
--port 3001
--hot
( 整个页面和整个项目打包 )// hot 不要写在配置文件里面,,否则的话还要配其余插件麻烦
"dev" : "webpack-dev-server --hot",
devServer : {
open : true,
port : 3001
}
复制代码
npm run dev
==> 不会打包的 ,只会把项目放到服务器里2.1 执行 : `npm run build` 对项目进行打包,生成dist文件
2.2 模拟本地服务器 : 安装 : `npm i -g http-server`
2.3 把dist文件里的内容放到服务器里便可, 直接运行`http-server`
复制代码
webpack 只能处理 js 文件,非 js(css.less.图片.字体等)处理处理不了, 借助 loader 加载器
建立一个 css 文件, 而后在 main.js
中引入 import '../css/index.css';
ul { style-list : none }
安装 : npm i -D style-loader css-loader
在 webpack.config.js
中,添加个新的配置项 module
在 module
中添加 loader
来处理 css
// loader
module: {
rules: [
//1.处理 css
// 注意点 use执行loader 顺序 从右往左
// css-loader : 读取css文件内容,将其转化为一个模块
// style-loader :拿到模块, 建立一个style标签,插入页面中
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]
}
复制代码
import '../css/index.less';
npm i -D less-loader less style-loader css-loader
module->rules
less
ul {
background-color: aqua;
li {
&:hover {
color: yellow;
}
}
}
复制代码
配置 :
{ test :/\.less$/, use : ['style-loader','css-loader','less-loader'] },
复制代码
设置背景图片.cls {
width: 300px;
height: 300px;
background: url('../css/4.jpg');
background-size: 100%;
}
安装 : npm i -D url-loader file-loader
url-loader (推荐) 和 file-loader 二选一便可
在 webpack.config.js 添加 loader 规则
// 处理图片
{ test : /\.(jpg|png)$/, use : ['url-loader'] },
复制代码
原始: background-image: url(../images/1.jpg);
处理后: background-image: url(9c9690b56876ea9b4d092c0baef31bb3.jpg);
复制代码
方式1 :{ test : /\.(jpg|png)$/, use : ['url-loader?limit=57417'] },
方式2 :
{
test: /\.(jpg|png)$/, use: [
{
loader: 'url-loader',
options: {
// 比57417这个小 => 转化为base64
// 大于等于这个57417值 => 不会转base64 内部调用 file-loader 加载图片
limit: 57417
}
}
]
},
复制代码
准备字体图标: 字体图标文件 iconfont
或者 从阿里矢量图标
里下载
拷贝到项目中的 css 文件夹中
在 main.js 中引入 css 文件
import '../css/iconfont/iconfont.css'
复制代码
使用 :
在 webpack.config.js 中配置
// 4. 处理字体图标
{ test:/\.(svg|woff|woff2|ttf|eot)$/,use:'url-loader'}
复制代码
var o = { ...obj }
在谷歌上能够,edge 就不能够npm i -D babel-core babel-loader@7
npm i -D babel-preset-env babel-preset-stage-2
babel-polyfill与babel-plugin-transform-runtime
也是作兼容处理的,之前都是用这个,兼容更早的{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
复制代码
.babelrc
{
"presets": [
"env",
"stage-2"
],
-----------
// 暂时不用
// 若是将来某一天真的用到了polify
"plugins": [
["transform-runtime", {
"helpers": false,
"polyfill": true,
"regenerator": true,
"moduleName": "babel-runtime"
}]
复制代码
var obj = {
name: 'zs',
age: 20
}
var o = { ...obj }
console.log(o)
复制代码
脚手架 2.X ==> 2.Xvue
脚手架 3.X ==> 3.X vue
vue-cli 是 vue 的脚手架工具
做用 : vue-cli 提供了一条命令, 咱们直接经过这条命令就能够快速的生成一个 vue 项目 (vue init XX
) 。 项目的基本结构、以及 webpack 配置项 所有配置 好了
为何会有脚手架工具 ???
由于 webpack 配置繁琐, 阻止一批想用 vue 可是不会 webpack 的开发人员,因此做者直接将全部 vue 项目中用到的配置所有帮你写好了,这样,就不须要开发人员再去配置基础 webpack 配置项了,使用 vue-cli 这个脚手架工具后,再也不用担忧 webpack 配置问题了, 咱们前端只须要写 vue 代码, 来实现功能便可
npm i -g vue-cli
vue init webpack 项目名称
vue init webpack vue-demo01
? Project name # 回车
? Project description # 回车
? Author # 回车
? Vue build standalone # => 运行时+编译 => 详见下面的问题1
? Install vue-router? # Yes
? Use ESLint to lint your code? # Yes => 详见下面的问题2
? Pick an ESLint preset Standard # standard
? Set up unit tests # No
? Setup e2e tests with Nightwatch? # No
? Should we run `npm install` for you after the project has been created? # (recommended) npm
复制代码
To get started:
cd vue-demo01
npm run dev
复制代码
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
第一遍:文件夹, 第二遍再细化文件
# build - webpack 相关配置
- build.js - 生产环境构建代码
- check-version.js 检查 node、npm 等版本
- util.js 构建工具相关
- vue-loader.config.js vue-loader 的配置文件
- webpack.base.conf.js - webpack 的基础配置
- webpack.dev.conf.js - webpack 开发环境配置
- webpack.prod.conf.js - webpack 发布环境配置
# config - vue 基本配置文件(好比:监听端口(17), 使用 eslint:(26))
- dev.env.js - 开发环境变量
- index.js 项目的一些配置
- prod.env.js 生成环境变量
# node_modules - node 安装的依赖包
# src - 资源文件夹, 之后咱们就在这个目录下写代码
- assets - 静态资源 (图片 css 都放在这)
- components - 公用组件
- router - 路由
- App.vue - 项目的根组件
- main.js - 项目的入口文件(总逻辑)
# static - 静态资源 (图片 json 数据之类的)
- .gitkeep git 保持文件,由于 git 上传,会忽略空文件夹
# .babelrc - babel 配置文件, (es6 语法编译配置,将 es6 转化为浏览器可以识别的代码)
# .editorconfig - 定义代码格式
- charset = utf-8 编码 utf8
- indent_style = space 缩进 空格
- indent_size = 2 缩进字符
- end_of_line = lf 回车做为换行的标记
- insert_final_newline = true 最近一空白行做为结尾
- trim_trailing_whitespace = true 清除最开始的空白
- 若是使用 ?
- 1. 安装 vscode 的 editorConfig for vscode
- 2. eslint 检测修复后
# .eslintignore - eslint 检测忽略的地方
- /build/
- /config/
- /dist/
- /\*.js 根目录下带.js 的
# .eslintrc.js - eslint 的配置文件
# .gitignore - git 的忽略文件
# .postcssrc.js - css 配置文件 (啥也没有处理)
# index.html - 页面入口
# package.json - 项目配置文件
复制代码
assets 静态资源
components 组件
App.vue 根组件 => 指定路由出口
app 中的 #app 仍是 index.html 中的 #app, app.vue 中的会覆盖前者 能够经过分别添加 title 属性验证一下
路由出口要写在 app.vue 组件模板中
main.js
Vue.config.productionTip = false
不要打印提示new Vue({
el: '#app', // 目标显示
router, // 挂载路由
components: { App }, // 注册组件 App
template: '<App/>' // 模板显示组件 app
})
复制代码
route/index.js => 路由
必定要记住 :Vue.use(Router)
模块化公工程中必定要安装路由插件 .js 就是一个模块
官网里 也提到 https://router.vuejs.org/zh/installation.html
参考 : vue.js => 安装 => 对不一样构建本版本的解释
// 须要编译器
new Vue({
template: '<div>{{ hi }}</div>'
})
// 不须要编译器
new Vue({
render (h) {
return h('div', this.hi)
}
})
复制代码
router/index.js =>
import HelloWorld from '@/components/HelloWorld'
import HelloWorld from 'C:/users/.../src/components/HelloWorld'
复制代码
概念 : ESLint 是在 JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。
如何使用 eslint ?
"editor.formatOnSave": true, //#每次保存的时候自动格式化
"eslint.autoFixOnSave": true, // #每次保存的时候将代码按eslint格式进行修复
"eslint.validate": [
{ "language": "html", "autoFix": true },
{ "language": "vue", "autoFix": true },
{ "language": "javascript", "autoFix": true },
{ "language": "wpy", "autoFix": true }
],
"prettier.eslintIntegration": true, // #让prettier使用eslint的代码格式进行校验
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
"editor.formatOnType": true //#让函数(名)和后面的括号之间加个空格
复制代码
关闭 Eslint :
dev.useEslint
设置为falsenpm run dev
测试 : 删除 main.js 中的 /* eslint-disable no-new */ 关闭后 会报波浪线,可是不会报错了
Prettier
eslint-disable-next-line # 忽略检测下一行 可使用单行注释/多行注释,其余都是多行注释
eslint-disable # 忽略当前整个文件
eslint-disable no-new # 忽略前面是new开头
复制代码
准备 :开启服务器+数据库
vue 项目学什么?
画图 : 接口访问路径 : 前端页面 ===> 接口服务器 ===> 数据库服务器 ==> 数据库
打开
phpStudy
,点击启动
打开 navicat
点击链接
: 建立一个MySQL
链接
用户名和密码 : root-root(不能乱写) 这个是和 config 里的配置同样的
建立一个数据库 : shop_admin
不要乱写, 选择倒数找到 unt-8
双击打开数据库
导入 sql语句
=> 右键运行 SQL 文件 => shop-api 最后一个 sql 文件
若是没有反应 : 表 => 右键刷新
shop-api
npm start
API 接口服务启动成功,占用端口 8888
http://localhost:8888/api/private/v1/login?username=admin&password=123456
项目使用接口 : (记得保存)
// shop-api里面有
复制代码
phpStudy
中的 mySql
shop-api
, 运行 npm start
导出 : export default
默认 只能导出一个
let str = 'abc'
let num = 20;
let obj = { name :'zs' }
export default num
// export default obj
复制代码
导入 : import
导入的名字能够任意
import res from './a.js'
console.log(res)
复制代码
**导出 : export **
// 逻辑模块
// 登陆一个函数
export let login = () => {
console.log('登陆');
}
// 注册一个函数
export let register = () => {
console.log('注册');
}
复制代码
导入 : import
// 方式1
import * as res from './a'
console.log(res);
res.login()
res.register()
// 方式2
import { login, register as reg } from './a'
login()
register()
复制代码
import axios from 'axios';
复制代码
vue init webpack shop_admin_35 清除不要的东西 (logo 和 hello world 组件 )
安装 : npm i vue-router 建立一个router文件夹 / router.js 实例化路由 导出路由模块 , main.js 引入 ,挂载到vue实例上
/**
准备工做
四个步骤
- 先把须要的组件建立出来 Login.vue Home.vue
- 走流程
1.先建立组件 /login/Login.vue 2.走流程
- 入口 : url手动写
- 规则 : {path :'/login', component: Login}
- 组件 : 引入便可
- 出口 : 在 app.vue 根组件 里 写一个出口
连接 : element-cn.eleme.io/#/zh-CN/com… 概念 : element 是一个(基于 vue 2.X )组件库
安装
: npm i element-ui ( -S == --save == 不写 ) (-D 开发阶段须要 发布阶段不须要)快速上手
:引入(main.js)
// 引入 element
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 安装一下 element-ui
Vue.use(ElementUI);
复制代码
测试 : 找到官网里的组件,拿到一个 按钮 注意点 :template 里面只能由一个根元素 one root element
el-form el-form-item
安装 axios 引入 使用
声明式导航 ==> 组件 标签 编程式导航 this.$router.push('/home') ==> 事件里
route : 路由对象 , 包含url的信息对象, (path query, params) 解析 地址 #后面的信息
注意1 : num='8' ==> 把字符串8 赋值给了num :num='8' ==> : 把 8 原来的类型赋值给num 注意2 : 若是想让label和input在一行 => 设置 label-width='100px' => el-form 若是想让 label 和 input 不在一行 =>不要设置 label-width