文章目录
55 webpack(上)
55.1 课前准备
55.2 用webpack转义JS
目标1: 用webpack转义JS
# ./node_modules/.bin/webpack等价
# 访问本地项目的webpack
npx webpack
55.3 初始化webpack.config.js
55.4 webpack配置entry和output
目标2: 理解文件名中hash的用途(便于添加缓存)
HTTP缓存, 响应头中的Cache-Control
首页是不能做缓存的, 没得通知的人了
目标3: 用webpack生成HTML
所有关于webpack的插件都–dev, 因为用户用不到.
目标4: 用webpack生成css: JS生成style方式
禁止双击预览html
http-server命令
# http-server . -c-1 等价
hs . -c-1
55.5 webpack-dev-server
--open会默认打开浏览器
webpack-dev-server --open
webpack dev server 不会生成dist目录, 是内存中就搞定了.
55.6 使用插件提取CSS文件
目标4: 用webpack生成css: CSS抽成文件
55.7 使用两个webpack config文件(上)
55.8 使用两个webpack config文件(中)
55.9 使用两个webpack config文件(下)
56 webpack(中)
56.1 loader vs plugin (上)
56.2 loader vs plugin (下)
面试经常问:
webpack loader 和webpack plugin
webpack loader是用来加载文件的, 比如: 可以加载JS文件, 把JS的文件转义成为低版本浏览器支持的JS文件.可以加载CSS文件, 将CSS的文件变成页面上的style标签或者其他处理还有就是加载图片文件, 对图片进行优化.
webpack plugin是用来扩展webpack的功能的, 比如: 通过HTMLWebpackPlugin插件, 用来生产HTML文件的, 还有就是通过MINICSSExtractPlugin插件, 把css抽取CSS代码成为CSS文件.
56.3 引入SCSS
目标5: 用webpack引入sass
node-sass过时了, 应该用dart-sass
github说要自己下载dart-sass或node-sass但是我没有下, 就可以运行程序了, 是之前下了么???
56.4 引入LESS和stylus
目标6: 用webpack引入LESS和stylus
SASS, LESS和Stylus完全没区别
56.5 使用file-loader引入图片
目标7: 用webpack引入图片
56.6 webpack import()懒加载
目标7: 用懒加载
面试经常问
懒加载就是不是进入页面的时候再加, 后续进行一些操作进行加载,比如点击之后, 然后加载出来.
56.7 github部署
master分支展示发开代码, gh-pages分支展示效果.
命令过多可以用sh脚本
git stash pop
回到上一个分支
git checkout -
57 【Vue全解】起手式
57.1 Vue在中国很火吗
57.2 自学线路图
57.3 使用@vue/cli 搭建项目
57.4 关于vue.js和vue.runtime.js的使用说明
vue.js 是完整版
vue.runtime.js是非完整版
57.5 vue.js和vue.runtime.js的使用
vue实例
57.6 vue单文件组件
打印Demo.vue的render
console.log(Demo.render.toString())
//打印结果
function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c("div", { staticClass: "red" }, [
_vm._v(" " + _vm._s(_vm.n) + " "),
_c("button", { on: { click: _vm.add } }, [_vm._v("+1")])
])
}
57.7 SEO基本原理
57.8 总结, 命名规范
58 Vue构造选项
58.1 创建Vue 实例
58.2 new Vue有哪些选项
el: 替换的HTML部分, 容器或者挂载点
template或render只能用一个, 因为template是完整版用, 非完整版是render
propsdata,renderError, errorCaptured, parent用的少
红色: 好好学, 必学, 几句话就可以说明白的.
黄色: 高级属性,
绿色: 直接可以会
蓝色: 不常用, 可学可不学
紫色: 比较特殊, 需要讲解一下
灰色: 很不常用, 用的时候看文档
filter表面上很有用, 但实际没啥用, 尽量不要用它. 用methods来代替它.
vue的 data 有bug
58.3 el和data选项
el 和.$mount("") 一样
58.4 methods, components, 四个钩子
为什么组件地方的data 要使用函数而不是对象.
简单来说就是如果遇到同时引用这个组件问题的时候, 因为引入组件的时候是需要实例化(new Vue(Demo))2次, 地址相同一个地方修改了, 另一个地方也相应修改了. 也就是这个组件的内存地址是一样的. 但是是函数返回回来的对象则是不同的地址.
除了main.js里面data 可以写对象, 其他组件地方都要写函数形式.
methods有个bug, 就是每次渲染都会执行, 即使没有变化但是也会执行.
模块化就是把独立的功能放到一个地方
引入组件的3种方式:
console.log(window.Vue)
const Vue = window.Vue
Vue.config.productionTip = false
import Demo from './Demo.vue'
Vue.component("Demo2", {
template: `
<div>demo2</div>
`
})
new Vue({
components:{
Demo,
Demo3: {
template: `
<div>demo3</div>
`
}
},
data() {
return {
n: 0,
array: [1, 2, 3, 4]
}
},
template: `
<div class="red">
{{n}}
<button @click="add">+1</button>
<Demo/>
<Demo2/>
<Demo3/>
<hr>
{{filter()}}
</div>
`,
methods: {
add(){
this.n += 1
},
filter(){
return this.array.filter(i => i % 2 === 0)
}
}
}).$mount('#ben')
组件: 可以组合的物件
文件名要用小写
组件用大写开头
面试点: destroyed怎么用呢
58.1 Props
加:
可以传data中的变量和methods的方法.
但是不加:
, 传的就是字符串
//data中的n
<Demo :message="n"/>
//传的字符串n
<Demo message="n"/>
<Demo :fn="add"/>
58.1 总结
59 【Vue全解】数据响应式
59.1 getter和setter
对应vue.js的文档 深入响应式原理部分
getter
let obj2 = {
姓: "高",
名: "圆圆",
get 姓名() {
return this.姓 + this.名;
},
age: 18
};
console.log("需求二:" + obj2.姓名);
// 总结:getter 就是这样用的。不加括号的函数,仅此而已。
setter
let obj3 = {
姓: "高",
名: "圆圆",
get 姓名() {
return this.姓 + this.名;
},
set 姓名(xxx){
this.姓 = xxx[0]
this.名 = xxx.slice(1)
},
age: 18
};
obj3.姓名 = '高媛媛'
console.log(`需求三:姓 ${obj3.姓},名 ${obj3.名}`)
//总结:setter 就是这样用的。用 = xxx 触发 set 函数
Object.defineProperty用法, 当对象实例化好后, 又想添加getter,setter时候使用.
let obj3 = {
姓: "高",
名: "圆圆",
get 姓名() {
return this.姓 + this.名;
},
set 姓名(xxx) {
this.姓 = xxx[0];
this.名 = xxx.slice(1);
},
age: 18
};
var _xxx = 0
Object.defineProperty(obj3, "xxx", {
get(){
return _xxx
},
set(value){
_xxx = value
}
})
obj3.姓名 = "高媛媛";
console.log(`需求三:姓 ${obj3.姓},名 ${obj3.名}`);
console.log(obj3)
59.2 Object.defineProperty
59.3 代理和监听
59.4 现场飙车看Vue.js源代码
59.5 小结
59.6 Vue的data的bug
59.7 数组的变异方法
59.8 纠错$set作用于数组时, 不会添加监听
59.9 ES 5的写法(不重要)
59.10 总结
60 【Vue全解】computed 和 watch
60.1 计算属性
性别不要用sex用gender
筛选男女代码1
// 引用完整版 Vue,方便讲解
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id += 1;
return { id, name, gender };
};
new Vue({
data() {
return {
users: [
createUser("方方", "男"),
createUser("圆圆", "女"),
createUser("小新", "男"),
createUser("小葵", "女")
],
displayUsers: []
};
},
created() {
this.displayUsers = this.users;
},
methods: {
change(String) {
if (String === "") {
this.displayUsers = this.users;
} else if (String === "male") {
this.displayUsers = this.users.filter(u => u.gender === "男");
} else if (String === "female") {
this.displayUsers = this.users.filter(u => u.gender === "女");
}
}
},
// 如何给三个按钮加事件处理函数
// 思路一:点击之后改 users
// 思路二:使用 computed
template: `
<div>
<div>
<button @click="change('')">全部</button>
<button @click="change('male')">男</button>
<button @click="change('female')">女</button>
</div>
<ul>
<li v-for="u in displayUsers" :key="u.id">
{{u.name}} - {{u.gender}}
</li>
</ul>
</div>
`
}).$mount("#app");
筛选男女代码2, 用计算属性
// 引用完整版 Vue,方便讲解
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id += 1;
return { id, name, gender };
};
new Vue({
data() {
return {
users: [
createUser("方方", "男"),
createUser("圆圆", "女"),
createUser("小新", "男"),
createUser("小葵", "女")
],
gender: ""
};
},
computed: {
displayUsers() {
const hash = {
male: "男",
female: "女"
};
const { users, gender } = this;
if (gender === "") {
return this.users;
} else if (typeof gender === "string") {
return users.filter(u => u.gender === hash[gender]);
} else {
throw new Error("gender 的值意外的值");
}
}
},
methods: {
setGender(string) {
this.gender = string;
}
},
// 如何给三个按钮加事件处理函数
// 思路一:点击之后改 users
// 思路二:使用 computed
template: `
<div>
<div>
<button @click="setGender('')">全部</button>
<button @click="setGender('male')">男</button>
<button @click="setGender('female')">女</button>
</div>
<ul>
<li v-for="u in displayUsers" :key="u.id">
{{u.name}} - {{u.gender}}
</li>
</ul>
</div>
`
}).$mount("#app");
60.2 watch的两个例子
60.3 watch的deep选项
60.4 完整用法
60.5 computed v.s. watch
61 【Vue全解】模板、指令与修饰符
61.1 三种写模版的方式
第一种: 完整版写法, 直接卸载HTML
第二种: 完整版写法, 写在template中
template的div会被替换
第三种:不完整写法, 写在xxx.vue中
<template></template>
中不是HTML语法是XML语法, 原因是更容易解析.
引入xxx.vue文件 import Xxx需要大写, 区分原生的标签.
61.2 v-html v-on v-bind v-if v-for v-show
{{}}
不支持if else
v-show是是通过css来实现的
61.3 指令与修饰符
61.4 .sync修饰符
vue中的<template></template>
的this可以直接省略
62. 【Vue全解】进阶构造属性
62.1 Directive指令
62.2 Mixin混入
62.3 Extends继承, 扩展
尽量先用Mixin
62.4 Provide和Inject
62.5 总结
63 【Vue全解】表单与v-model
63.1 基本用法
对应vue.js的表单输入绑定章
- 输入框
<template>
<div id="app">
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
<button @click="x">点击</button>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return{
message: "aaa"
}
},
methods:{
x(){
this.message = "Jonathon Ben"
}
}
}
</script>
- 多行文本
<template>
<div id="app">
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<p>Message is: {{ message }}</p>
<button @click="x">点击</button>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return{
message: "aaa"
}
},
methods:{
x(){
this.message = "Jonathon Ben"
}
}
}
</script>
有了Vue之后就尽量少用id
- 复选框
<template>
<div id="app">
爱好: {{x}}
<hr>
<label>
<input type="checkbox" v-model="x" value="抽烟">
<span>抽烟</span>
</label>
<label>
<input type="checkbox" v-model="x" value="喝酒">
<span>喝酒</span>
</label>
<label>
<input type="checkbox" v-model="x" value="打牌">
<span>打牌</span>
</label>
<label>
<!-- value中的值需要是数字, 使用动态绑定 -->
<input type="checkbox" v-model="x" :value="1">
<span>1</span>
</label>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: "aaa",
x: []
}
},
}
</script>
- 单选框
<template>
<div id="app">
爱好: {{x}}
<hr>
<label>
<input type="radio" v-model="x" name="want" value="抽烟">
<span>抽烟</span>
</label>
<label>
<input type="radio" v-model="x" name="want" value="喝酒">
<span>喝酒</span>
</label>
<label>
<input type="radio" v-model="x" name="want" value="打牌">
<span>打牌</span>
</label>
<label>
<!-- value中的值需要是数字, 使用动态绑定 -->
<input type="radio" v-model="x" name="want" :value="1">
<span>1</span>
</label>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: "aaa",
x: "喝酒"
}
},
}
</script>
- 下拉框
<template>
<div id="app">
爱好: {{x}}
<hr>
<select v-model="x">
<option value="">请选择</option>
<option v-for="item in array" :value="item.value" :key="item.value">{{item.text}}</option>
</select>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
array: [
{
text: "抽烟", value: "抽烟"
},
{
text: "喝酒", value: "喝酒"
},
{
text: "打牌", value: "打牌"
},
{
text: 1, value: 1
},
],
message: "aaa",
x: ""
}
},
}
</script>
- 下拉多选框
<template>
<div id="app">
爱好: {{x}}
<hr>
<select multiple v-model="x">
<option value="">请选择</option>
<option v-for="item in array" :value="item.value" :key="item.value">{{item.text}}</option>
</select>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
array: [
{
text: "抽烟", value: "抽烟"
},
{
text: "喝酒", value: "喝酒"
},
{
text: "打牌", value: "打牌"
},
{
text: 1, value: 1
},
],
message: "aaa",
x: ""
}
},
}
</script>
- form表单
form 添加了button后, 默认回车就可以提交了
<template>
<div id="app">
登录{{user.username + user.password}}
<hr>
<!-- .prevent阻止默认事件 -->
<form @submit.prevent="onSubmit">
<label>
<span>用户名</span>
<input type="text" v-model="user.username">
</label>
<br>
<label>
<span>密码:</span>
<input type="password" v-model="user.password">
</label>
<!-- 注释为button标准写法 -->
<!-- <button type="submit">提交</button> -->
<button>提交</button>
</form>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
user: {
username: "",
password: ""
}
}
},
methods:{
onSubmit(){
console.log(this.user)
}
}
}
</script>
63.2 三个修饰器
- .lazy
v-model
1 input事件, 键盘 鼠标 等任何输入设备
2 change事件, 只在input失去焦点时触发 - .number
过滤只留下数字 - .trim
消除左右两边空格
<template>
<div id="app">
登录{{user}}
<hr>
<!-- .prevent阻止默认事件 -->
<form @submit.prevent="onSubmit">
<label>
<span>用户名</span>
<input type="text" v-model.lazy.trim="user.username">
</label>
<br>
<label>
<span>年龄</span>
<input type="text" v-model.number="user.age">
</label>
<br>
<label>
<span>密码:</span>
<input type="password" v-model="user.password">
</label>
<!-- 注释为button标准写法 -->
<!-- <button type="submit">提交</button> -->
<button>提交</button>
</form>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
user: {
username: "",
age: 0,
password: ""
}
}
},
methods: {
onSubmit() {
console.log(this.user)
}
}
}
</script>
63.3 v-model
input是一个元素所以要用$event.target.value
v-model
的等价写法<input type="text" :value="user.username" @input="user.username = $event.target.value">
app.vue
<template>
<div id="app">
登录{{user}}
<hr>
<!-- .prevent阻止默认事件 -->
<form @submit.prevent="onSubmit">
<label>
<span>用户名</span>
<!--自定义input只需要$event, 可能为了input区分-->
<MyInput :value="user.username" @input="user.username = $event"/>
</label>
<br>
<label>
<span>年龄</span>
<input type="text" v-model.number="user.age">
</label>
<br>
<label>
<span>密码:</span>
<input type="password" v-model="user.password">
</label>
<!-- 注释为button标准写法 -->
<!-- <button type="submit">提交</button> -->
<button>提交</button>
</form>
</div>
</template>
<script>
import MyInput from "./MyInput.vue";
export default {
name: 'App',
components:{
MyInput
},
data() {
return {
user: {
username: "",
age: 0,
password: ""
}
}
},
methods: {
onSubmit() {
console.log(this.user)
}
}
}
</script>
MyInput.vue
<template>
<div class="red warpper" >
<input type="text" :value="value" @input="$emit('input', $event.target.value)
">
</div>
</template>
<script>
export default {
name: "MyInput",
props:{
value:{
type: String
}
}
}
</script>
<style scoped>
.red{
background: red;
}
.warpper{
display: inline-block;
}
</style>
63.4 如何使用ant-design-vue
如何查看一个项目是否维护,eg: element 查看commit最后提交日期 不要使用3个月内没有维护的前端组件. 因为前端变化特别快.
函数使用on不使用handle, 一是因为简洁, 而是表达直观.
先安装ant design
main.js
import Vue from 'vue';
import Antd from 'ant-design-vue';
import App from './App';
import 'ant-design-vue/dist/antd.css';
Vue.use(Antd);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
app.vue
<template>
<a-form
id="components-form-demo-normal-login"
:form="form"
class="login-form"
@submit.prevent="onSubmit"
>
<a-form-item>
<a-input
v-decorator="[
'用户名:',
{ rules: [
{ required: true, message: '用户名不能为空' }] },
]"
placeholder="用户名"
>
<a-icon slot="prefix" type="user" style="color: rgba(0,0,0,.25)"/>
</a-input>
</a-form-item>
<a-form-item>
<a-input
v-decorator="[
'密码:',
{ rules: [{ required: true, message: '密码不能为空' }] },
]"
type="password"
placeholder="密码"
>
<a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)"/>
</a-input>
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit" class="login-form-button">登录</a-button>
</a-form-item>
</a-form>
</template>
<script>
export default {
name: 'App',
beforeCreate() {
this.form = this.$form.createForm(this, {name: 'normal_login'});
},
methods: {
onSubmit() {
// e.preventDefault();
// @submit.prevent="onSubmit" 等价于.prevent
this.form.validateFields((err, values) => {
if (!err) {
console.log('data: ', values);
} else {
console.log("err: ", err);
}
});
}
}
}
</script>
<style scoped>
#components-form-demo-normal-login .login-form {
max-width: 300px;
}
#components-form-demo-normal-login .login-form-forgot {
float: right;
}
#components-form-demo-normal-login .login-form-button {
width: 100%;
}
</style>
64 【Vue全解】Vue Router - 前端路由实现思路
64.1 目录
64.2 路由是什么
路由就是分发请求
路由器就是 分发请求的机器.
64.3 优化代码
index.html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>router</title>
</head>
<body>
<a href="#1">go to 1</a>
<a href="#2">go to 2</a>
<a href="#3">go to 3</a>
<a href="#4">go to 4</a>
<div id="app"></div>
<div id="div1" style="display: none">1</div>
<div id="div2" style="display: none">2</div>
<div id="div3" style="display: none">3</div>
<div id="div4" style="display: none">4</div>
<div id="div404" style="display: none">404</div>
<script src="./src/index.js"></script>
</body>
</html>
index.js
function route(){
//获取用户想去哪
let number = window.location.hash.substr(1) || 1
let app = document.querySelector("#app")
//获取界面
let div = document.querySelector(`#div${number}`)
if(!div){
div = document.querySelector("#div404")
}
//渲染界面
div.style.display = "block"
if(app.children.length > 0){
app.children[0].style.display = "none"
document.body.appendChild(app.children[0])
}
//展示界面
app.appendChild(div)
}
route()
//检测hash改变
window.addEventListener("hashchange", ()=>{
console.log("路由改变了");
route()
})
64.4 路由表
index.html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>router</title>
</head>
<body>
<a href="#1">go to 1</a>
<a href="#2">go to 2</a>
<a href="#3">go to 3</a>
<a href="#4">go to 4</a>
<div id="app"></div>
<div id="div404" style="display: none">404</div>
<script src="./src/index.js"></script>
</body>
</html>
index.js
const div1 = document.createElement("div")
div1.innerHTML = "1"
const div2 = document.createElement("div")
div2.innerHTML = "2"
const div3 = document.createElement("div")
div3.innerHTML = "3"
const div4 = document.createElement("div")
div4.innerHTML = "4"
const routeTable = {
"1": div1,
"2": div2,
"3": div3,
"4": div4
}
function route(){
//获取用户想去哪
let number = window.location.hash.substr(1) || 1
let app = document.querySelector("#app")
//获取界面
let div = routeTable[number.toString()]
if(!div){
div = document.querySelector("#div404")
}
//渲染界面
div.style.display = "block"
//展示界面
app.innerHTML = ""
app.appendChild(div)
}
route()
//检测hash改变
window.addEventListener("hashchange", ()=>{
console.log("路由改变了");
route()
})
嵌套路由
64.5 history模式
hashbang 谷歌针对hash路由问题的方案
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>router</title>
</head>
<body>
<a class="link" href="/1">go to 1</a>
<a class="link" href="/2">go to 2</a>
<a class="link" href="/3">go to 3</a>
<a class="link" href="/4">go to 4</a>
<div id="app"></div>
<div id="div404" style="display: none">404</div>
<script src="./src/index.js"></script>
</body>
</html>
index.js
let app = document.querySelector("#app");
const div1 = document.createElement("div");
div1.innerHTML = "1";
const div2 = document.createElement("div");
div2.innerHTML = "2";
const div3 = document.createElement("div");
div3.innerHTML = "3";
const div4 = document.createElement("div");
div4.innerHTML = "4";
const routeTable = {
"/1": div1,
"/2": div2,
"/3": div3,
"/4": div4
};
function route(container) {
//获取用户想去哪
let number = window.location.pathname;
console.log("number: " + number);
if (number === "/") {
number = "/1";
}
//获取界面
let div = routeTable[number.toString()];
if (!div) {
div = document.querySelector("#div404");
}
//渲染界面
div.style.display = "block";
//展示界面
container.innerHTML = "";
container.appendChild(div);
}
route(app);
const allA = document.querySelectorAll("a.link");
for (let a of allA) {
a.addEventListener("click", e => {
e.preventDefault();
const href = a.getAttribute("href");
window.history.pushState(null, `page ${href}`, href);
//通知
onStateChagne();
});
}
function onStateChagne() {
console.log("state change");
route(app);
}
64.6 history和hash模式的对比
65.7 memory模式
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>router</title>
</head>
<body>
<a class="link" href="/1">go to 1</a>
<a class="link" href="/2">go to 2</a>
<a class="link" href="/3">go to 3</a>
<a class="link" href="/4">go to 4</a>
<div id="app"></div>
<div id="div404" style="display: none">404</div>
<script src="./src/index.js"></script>
</body>
</html>
index.js
let app = document.querySelector("#app");
const div1 = document.createElement("div");
div1.innerHTML = "1";
const div2 = document.createElement("div");
div2.innerHTML = "2";
const div3 = document.createElement("div");
div3.innerHTML = "3";
const div4 = document.createElement("div");
div4.innerHTML = "4";
const routeTable = {
"/1": div1,
"/2": div2,
"/3": div3,
"/4": div4
};
function route(container) {
//获取用户想去哪
let number = window.localStorage.getItem("xxx");
console.log("number: " + number);
if (!number) {
number = "/1";
}
//获取界面
let div = routeTable[number.toString()];
if (!div) {
div = document.querySelector("#div404");
}
//渲染界面
div.style.display = "block";
//展示界面
container.innerHTML = "";
container.appendChild(div);
}
route(app);
const allA = document.querySelectorAll("a.link");
for (let a of allA) {
a.addEventListener("click", e => {
e.preventDefault();
const href = a.getAttribute("href");
window.localStorage.setItem("xxx", href);
//通知
onStateChagne();
});
}
function onStateChagne() {
console.log("state change");
route(app);
}
65.8 如何阅读VueRouter源代码
66【Vue全解】深入讲解 Vue 动画原理
66.1【Vue全解】Vue动画方式1- CSS transition
css 有些属性不需要初始值, 有些属性需要初始值.
不要用show这个单词, 是动词, 用visible
66.2【Vue全解】Vue动画方式2- CSS animation
animation.css库 用来animation动画
66.3【Vue全解】Vue动画方式3- JS操作动画
velocity是用js来控制动画
66.4【Vue全解】Vue动画方式4- 多元素动画
动态组件可以用作tabbar
66.5【Vue全解】列表动画
列表过渡经常用到, 而且复杂
transition-group