目录
习题详解
i) 有两个大标题,电视和手机,点击对应的标题,渲染对应的数据
ii) 一个字典作为一个显示单位,定义一个子组件进行渲染(涉及父子组件传参)
3、在第2题基础上,页面最下方有一个 h2 标签,用来渲染用户当前选择的广告(点击哪个广告就是选中哪个广告)
i)当没有点击任何广告,h2 标签显示:未选中任何广告
ii)当点击其中一个广告,如tv1,h2 标签显示:tv1被选中
'''
<button @click="select = 'tv'" :class="{active: select === 'tv'}">tv</button>
...
<div class="wrap" v-if="select === 'tv'">
<tag v-for="tv in ad_data.tv" :xxx="tv" :key="tv.title" @yyy="choice"></tag> # v-for指令需要给循环的标签或组件添加key属性设定主键索引缓存
</div>
...
<div class="nav"><h2>{{selectContent}}</h2></div>
let tag = {
props: ['xxx'],
template: `
<div class="box" @click="fn(xxx.title)">
<img :src="xxx.img" alt="">
<h2>{{xxx.title}}</h2>
</div>
`,
methods: {
fn(m) {
this.$emit('yyy', m);
},
}
};
new Vue({
...
components: {
tag,
},
data: {
ad_data,
select: 'tv',
selectContent: '未选中任何广告'
},
methods: {
choice(a) {
if (a) {
this.selectContent = `${a}被选中` # js语法中的模板字符串
}
},
},
});
'''
js原型补充
'''
function A() {
}
let a1 = new A();
console.log(a1.num); // undefined
A.prototype.num = 100; // 为A类添加原型
console.log(a1.num); // 100
// ES6定义类的语法
class B {
constructor(name) { // 构造器自定义对象属性
this.name = name
}
}
let b1 = new B('蔡启龙');
console.log(b1.name); // 蔡启龙
// 推导
Vue.prototype.$ajax = ... // 为所有Vue对象添加$ajax属性
'''
Vue项目环境搭建
- vue: 类似于django
- node: 类似于python
- npm: 类似于pip
'''
let a = 1;
undefined
console.log(a);
1
undefined // console.log函数无返回值, 所以多出一个undefined结果
'''
- 在系统环境中敲npm|pip可以查看npm|pip指令, 敲npm list|pip list可以查看npm或pip已安装过的包
- 安装cnpm: 在系统环境中敲
npm install -g cnpm --registry=https://registry.npm.taobao.org
, cnpm是国内安装源 - 安装脚手架: 在系统环境中敲
cnpm install -g @vue/cli
- 创建项目: 在系统环境中敲
vue project my-project
或vue u
- 在创建选项中, 选择安装babel插件, 作用: JavaScript编译器, 将es6转成es5
vue根据配置重新构建依赖
-
新建文件夹-->存放public文件夹, src文件夹, package.json文件
-
打开cmd, 输入执行:
cnpm install
, 会根据package.json文件重新构建依赖 -
如果后期缺少某个依赖, cd到项目所在目录手动安装, 例如
cnpm install ajax
-
运行项目: cd到项目所在目录, 执行
cnpm run serve
-
src-->router-->index.js, 修改内容:
''' ... import About from '../views/About.vue' ... const routes = [ ... { ... component: () => About } ] ... '''
pycharm管理vue项目
Edit Configurations-->npm-->Scripts-->serve
Vue项目目录介绍
node_modules:
- 当前项目所有依赖, 一般不可移植给其他电脑
public:
- favicon.ico: 图标
- index.html: 项目唯一主页
src:
- assets: 资源文件夹, 一般建三个子文件夹: img, css, js
- components: 小组件, 打开视图组件文件xxx.vue需要下载vue.js
- views: 页面视图组件
- router: 路由脚本
- store: 仓库脚本
- App.vue: 根视图组件
- main.js: 全局脚本文件
package.json: 主要的配置文件
Vue项目生命周期
资源导入说明
main.js是整个项目的入口
vue语法中的 import App from './App'
, 类似于python中的 from './App' import xxx as App
v-projsrcmain.js
- import 别名 from 资源
- 资源直接写名字时, 资源在node_modules文件夹中
- 资源写路径时, 例如:
'./App.vue'
,.
表示当前文件所在文件夹的路径, - 按路径导入资源时可以省略后缀, 例如:
'./App.vue'
, 等价于'./App'
生命周期流程
- 启动项目, 加载主脚本文件main.js
- 加载vue环境, 创建根组件完成渲染
- 加载系统已有的第三方环境: router, store
- 加载自定义的第三方环境与自己配置的环境
- router被加载, 就会解析router文件夹下的index.js脚本文件, 完成路由---组件的映射关系
- 新建视图组件: v-projsrcviews-->xxx.vue,
- 在v-projsrc outerindex.js中配置视图组件,
- 设置路由跳转:
<router-link to="/about">About</router-link>
代码
'''
# v-projpublicindex.html
...
<html lang="en">
...
<body>
...
<div id="my_app"></div>
...
</body>
</html>
# v-projsrcmain.js
import Vue from 'vue' # 导入node_modules文件夹中的资源
import App from './App'
import router from './router'
import store from './store'
// 简写:
new Vue({
router,
store,
render: h => h(App)
}).$mount('#my_app'); # 将根视图组件对应的数据渲染到publicindex.html对应的挂载点
// 完整写法:
// new Vue({
// el: '#my_app',
// router: router,
// store: store,
// render: function (handle) {
// return handle(App);
// }
// });
# 在v-projsrcviews中新建User.vue视图组件
<template> # 视图组件通过routerindex.js中对应配置渲染到根视图组件中的<router-view/>时的标识
<span>User页面</span>
</template>
...
# v-projsrc
outerindex.js
import Vue from 'vue'
import VueRouter from 'vue-router'
...
import User from '../views/User.vue'
Vue.use(VueRouter);
const routes = [
...,
{
path: '/user',
...
...
component: User
},
];
const router = new VueRouter({
routes
});
export default router
# v-projsrcApp.vue
<template> # main.js中对应函数读取根视图数据并渲染到挂载点的标识
<div id="xxx"> # 根视图组件必须有且仅有一个块级根标签
...
<router-link to="/user">User</router-link> # 设置路由跳转
...
<router-view/> # 页面视图组件在根组件中的渲染占位符, 通常为一个, 也可以为多个
</div>
</template>
...
'''
小组件的使用
template标签负责组件的html结构, 有且只能有一个根标签
script标签负责组件的js逻辑,
- 组件需要要在script标签中通过vue语法导出外界才能导入使用该组件
- 如果没有在script标签中通过vue语法导出, 则默认只加载页面HTML结构
style标签负责组件的css样式, scoped参数控制样式的组件化, 使样式只在对应的组件内部起作用
'''
# v-projsrccomponentscomponent1.vue
<template>
<div><h1>小组件</h1></div>
</template>
<script>
export default {
data() {
return {};
},
methods: {},
}
</script>
<style scoped>
h1 {
color: red;
}
</style>
# v-projsrcviewsHome2.vue
<template>
<div>
<h1>Home页面组件</h1>
<component1></component1> # 页面组件中渲染小组件
</div>
</template>
<script>
import component1 from '../components/component1' # 页面组件中导入小组件
export default {
components: {
component1, # 页面组件中注册小组件
},
}
</script>
<style scoped>
h1 {
color: aqua;
}
</style>
'''
配置自定义全局样式
- 在v-projsrcassets文件夹中新建css文件夹并新建css文件, 然后在该css文件中书写自定义的全局css样式
- 在main.js文件中导入全局css样式文件
'''
# v-projsrcassetscssglobal.css
ul {
list-style: none; /*去除无序列表项的小圆点*/
}
# day68v-projsrcmain.js
// 配置全局样式
import './assets/css/global.css' // 只需加载文件时的导入方式
// 其他配置方式:
// import xxx from './assets/css/global.css' // 要使用文件内容时的导入方式
// import '@/assets/css/global.css' // @代表src文件夹的绝对路径
// require('@/assets/css/global.css'); // 官方推荐加载静态文件的方式, 可以用变量接收结果
'''
路由逻辑跳转
导航栏组件及其样式: copy
<router-link>
通过to
属性指定目标地址, 默认渲染成带有正确链接的<a>
标签, 例如<router-link to="/course">课程页</router-link>
:<a href="#/course" class="">课程页</a>
- 当目标路由成功激活时, 链接元素自动设置一个表示激活的 CSS 类名
class="router-link-exact-active router-link-active"
: router-link-exact-active是精确匹配规则, router-link-active是全包含匹配规则
'''
# Nav.vue
<li class="logo" @click="goHome"><img src="@/assets/img/lufei.svg" alt=""></li>
<li class="route">
# <router-link to="/course">课程页</router-link>
<router-link :to="{name: 'course'}">课程页</router-link> <!--类似于前端的反向解析-->
</li>
<script>
export default {
name: "Nav", // 组件的名字
methods: {
goHome() {
// console.log(this.$router); // VueRouter {…}, 控制路由跳转
// console.log(this.$route); // {name: "home", ..., path: "/", ...}, 控制路由数据
if (this.$route.path !== '/') { // 判断当前路由是否为home路由, 避免跳转重复路由报错
// this.$router.push('/');
// this.$router.go(-1) // go是历史记录前进后退, 正为前进, 负为后退, 数字为步数
this.$router.push({name: 'home'})
}
},
}
}
</script>
# v-projsrc
outerindex.js
...
const routes = [
{
path: '/',
name: 'home', // 类似于反向解析中url的别名
component: Home
},
...
];
...
'''
路由重定向
'''
# v-projsrc
outerindex.js
...
const routes = [
...,
{
path: '/xxx',
redirect: '/'
},
];
...
'''
组件的生命周期钩子
- 一个组件从创建到销毁的过程中, 几个特殊的时间节点回调的方法
- 这些方法都是vue组件实例的成员
'''
# v-projsrcviewsHome.vue
<script>
export default {
data() {
return {
back_data: 'Owen',
};
},
beforeCreate() {
console.log('Home组件要被创建了...');
console.log(this.back_data) // undefined
},
created() { // 在该钩子中完成前端对后端数据的请求
console.log('Home组件创建成功!');
console.log(this.back_data) // Owen
},
beforeMount() {
console.log('Home组件准备挂载...');
},
mounted() { // 对于特别耗时的数据请求, 可以延后到组件初步加载成功后, 在该钩子中继续请求
console.log('Home组件挂载完成!');
},
destroyed() { // 应用场景: 离开页面时可以在该钩子中进行二次确认
console.log('Home组件销毁成功了!');
},
}
</script>
'''
路由传参
Course.vue
- 在created钩子中前端对后端数据的请求
- 如果组件加载静态数据并将其当做参数传给其他组件使用, 需要用require方法
'''
# v-projsrcviewsCourse.vue
<template>
<div class="course">
...
<CourseTag v-for="course in courses" :course="course"></CourseTag>
...
</div>
</template>
<script>
...
import CourseTag from '../components/CourseTag'
export default {
...
components: {
...
CourseTag,
},
data() {
return {
courses: [],
};
},
created() { // 在该钩子中完成前端对后端数据的请求
// 前后端开发时从后端获取数据
this.courses = [
{
id: 1,
title: '西游记',
// 如果组件加载静态数据并将其当做参数传给其他组件使用, 需要用require方法
img: require('../assets/img/111.jpg'), // 实际项目中为后端图片链接
// img: '../assets/img/111.jpg' // 直接写路径无法加载图片
},
...
]
},
mounted() { // 如果是特别耗时的数据请求, 可以延后到组件初步加载成功后, 再慢慢请求
console.log('Course组件挂载完成!');
},
destroyed() { // 应用场景: 例如二次确认是否离开页面
console.log('Course组件销毁成功了!');
},
}
</script>
'''
CourseTag.vue
- 第一种路由传参: 在url后面通过?拼接参数
- 第二种路由传参: 在url中通过模板字符串传递参数变量
- this.$router.push: 控制路由跳转
'''
# v-projsrccomponentsCourseTag.vue
<template>
<div class="box">
<img :src="course.img" alt="" @click="goDetail(course.id)">
# 第一种路由传参: 在url后面通过?拼接参数
# <router-link :to="`/course/detail?pk=${course.id}`"><h2>{{course.title}}</h2></router-link>
"""
<router-link :to="{
name: 'course-detail',
query: {pk: course.id}
}">
<h2>{{course.title}}</h2>
</router-link>
"""
# 第二种路由传参: 在url中通过模板字符串传递参数变量
<router-link :to="`/course/${course.id}/detail`"><h2>{{course.title}}</h2></router-link>
</div>
</template>
<script>
export default {
props: ['course',],
methods: {
goDetail(pk) {
// this.$router.push(`/course/detail?pk=${pk}`);
this.$router.push({
// path: '/course/detail',
name: 'course-detail', // 控制点击后跳转的url
query: {pk: pk} // 控制跳转的url?后拼接的参数
})
}
}
};
</script>
'''
index.js
'''
...
import CourseDetail from '../views/CourseDetail.vue'
...
const routes = [
...
{
// 第一种路由传参对应的配置
// path: '/course/detail',
// 第二种路由传参对应的配置
path: '/course/:pk/detail', // :pk为vue语法中的有名分组
name: 'course-detail',
component: CourseDetail
},
];
...
'''
CourseDetail.vue
- 在标签中获取当前组件中的数据可以直接通过变量名获取, 而不需要使用this.的形式
- this.$route存放当前页的url信息
'''
# v-projsrcviewsCourseDetail.vue
<template>
<div class="course-detail">
<button @click="$router.go(-1)">返回课程页</button> <!--在标签中不需要通过this.获取-->
...
</div>
</template>
<script>
export default {
data() {
return {
pk: 0
};
},
created() {
// 获取路由传递的参数: 课程id
// console.log(this.$route); // {..., path: "/course/detail", ..., query: {pk: "3"}, …}
// this.pk = this.$route.query.pk; // query接收路径?后面传递过来的参数
this.pk = this.$route.params.pk || this.$route.query.pk; // params接收根据有名分组从路径字符串匹配到的参数
},
}
</script>
'''