技术标签: 前端 vue.js javascript
01 安装vue-cli脚手架#
npm install -g @vue/cli
02 查看vue脚手架版本#
出现版本号表示成功
vue --version
03 创建一个新项目#
创建项目
vue create hello-world // 1.创建项目
运行项目
cd hello-world // 2.进入项目文件夹
npm run serve // 3.运行项目
// 根目录新增vue.config.js
module.exports = {
lintOnSave: false
}
如果vue组件提示红色错误,如下图
解决办法: 文件 -> 首选项 -> 设置 然后输入eslint -> 选择Vetur -> 把√取消即可
vue开发调试工具
npm install less [email protected] --save-dev
在vue文件这样写即可, scoped表示样式只在当前文件有效, 不会影响其他组件
ps: less-loader要安装6.0版本, 不然有兼容问题
<style lang="less" scoped>
.box {
.text {
color: red;
}
}
</style>
(1)一个简单路由配置#
npm i vue-router
安装路由插件import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
// 路由数组
const routes = [
{
path: '/product',
component: ()=>import('@/views/product/index.vue')
},
{
path: '/cart',
component: ()=>import('@/views/cart/index.vue')
},
]
const router = new Router({
routes
})
export default router;
// main.js 代码
import Vue from 'vue'
import App from './App.vue'
import router from './router/index'
Vue.config.productionTip = false
new Vue({
// 把router挂载到vue实例
router,
render: h => h(App),
}).$mount('#app')
(2) router-view#
<template>
<div id="app">
<!-- 路由出口 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
components: {},
};
</script>
(3) 路由跳转#
// 方式一
<router-link to="/cart">cart</router-link>
// 方式二
this.$router.push('/cart');
(4) 子路由配置#
使用子路由进行模块路由配置,结构比较分明 比如我们的网站有商品模块,有列表页面和详情页面, 路由如下 /product 商品模块总路由 /prodcut/list 子路由 /product/detail 子路由
{
path: '/product',
component: () => import('@/views/product/index'),
children: [
{
path: 'list',
component: ()=>import('@/views/product/children/list')
},
{
path: 'detail',
component: ()=>import('@/views/product/children/detail')
}
]
}
(5) active-class#
active-class是vue-router模块的router-link组件中的属性,用来做选中样式的切换;
<router-link to="/" active-class="on" exact>首页</router-link>
<router-link to="/product" active-class="on">product</router-link>
<router-link to="/cart" active-class="on">cart</router-link>
<router-link to="/my" active-class="on">my</router-link>
<router-link to="/order" active-class="on">order</router-link>
(6) history模式#
vue2配置方式
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面
使用history需要后端支持, vue-cli创建的devServer可以支持
const router = new VueRouter({
mode: 'history', // 默认hash
routes: [...]
})
vue3配置方式
const router = createRouter({
history: createWebHistory(), // history模式
//history: createWebHashHistory(), // hash模式
routes
});
(7) redirect重定向#
当访问 '/', 我们使用redirect使它默认跳到 '/product'
{
path: '/',
redirect: '/product'
},
(8) 404配置#
假如用户访问了一个没有的路由, 我们让它跳转到404页面
{
path: '*',
component:()=>import('@/components/NotFound')
}
知识点(背诵):
1.父传子#
// 例子1: 使用普通属性
// demo.vue
<template>
<div>
<h3>父组件</h3>
<hr />
<Son msg="hello world" username="张三"/>
</div>
</template>
<script>
import Son from "./Son";
export default {
components: {
Son,
},
};
</script>
// Son.vue
<template>
<div>
<h4>子组件</h4>
<p>msg: {
{ msg }}</p>
<p>username: {
{ username }}</p>
</div>
</template>
<script>
export default {
props: ["msg", "username"],
};
</script>
// 例子2: 使用绑定属性(可传变量)
// demo.vue
<template>
<div>
<h3>父组件</h3>
<hr />
<Son :msg="msg" :username="username" />
</div>
</template>
<script>
import Son from "./Son";
export default {
components: {
Son,
},
data() {
return {
msg: '哈哈哈',
username: '李四'
};
},
};
</script>
// Son.vue
<template>
<div>
<h4>子组件</h4>
<p>msg: {
{ msg }}</p>
<p>username: {
{ username }}</p>
</div>
</template>
<script>
export default {
props: ["msg", "username"],
};
</script>
父传子实践: 把首页拆分为多个组件 技巧: 如果某个部分只是做展示用, 尽量把它变成子组件
2. 子传父#
// 例子1: 一个简单的例子
// demo.vue
<template>
<div>
<h3>父组件</h3>
<hr />
<Son @aaa="say"/>
</div>
</template>
<script>
import Son from "./Son";
export default {
components: {
Son,
},
data() {
return {
};
},
methods: {
say(data) {
alert(data)
}
}
};
</script>
// 子组件
<template>
<div>
<h4>子组件</h4>
<button @click="$emit('aaa','我是子组件')">点击</button>
</div>
</template>
<script>
export default {
props: ["msg", "username"],
};
</script>
import axios from "axios";
import Vue from "vue";
import { Toast } from "vant";
Vue.use(Toast);
const service = axios.create({
baseURL: "http://huruqing.cn:3003",
timeout: 50000, // 请求超时时间(因为需要调试后台,所以设置得比较大)
});
// request 对请求进行拦截
service.interceptors.request.use(
(config) => {
// 开启loading
Toast.loading({
message: "加载中...",
forbidClick: true,
loadingType: "spinner",
});
// 请求头添加token
config.headers["token"] =
"gg12j3h4ghj2g134kj1g234gh12jh34k12h34g12kjh34kh1g";
return config;
},
(error) => {
Promise.reject(error);
}
);
// response 响应拦截器
service.interceptors.response.use(
(response) => {
Toast.clear();
const res = response.data;
if (res.code == 666) {
return res;
} else {
// 成功连接到后台, 但是没有返回正确的数据
Toast.fail(res.msg);
}
},
(error) => {
Toast.clear();
// 跟后台连接失败
Toast.fail("网络异常,请稍后再试");
}
);
export default service;
// 注册全局组件除了多了个template之外,其它跟平时写组件类似
// 在main.js,实例化vue组件之前执行以下代码
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">你打了我 {
{ count }} 次</button>'
})
// 在其他组件就可以使用
<template>
<div>
<button-counter></button-counter>
</div>
</template>
// 改造checkbox, 官网例子
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
// 然后就可以像下面这样来使用
<template>
<div>
<base-checkbox v-model="flag"></base-checkbox>
<p>{
{flag}}</p>
</div>
</template>
<script>
export default {
data: function () {
return {
flag: false
};
},
}
</script>
// 另外需要在根目录的vue.config.js中开启运行时编译
module.exports = {
runtimeCompiler: true
}
元素作为承载分发内容的出口 一个内存插槽, 当内存插上之后,插槽就可以接收来自内存的信息, slot取名插槽含义也贴切, 在子组件配置插槽slot, 当父组件"插"信息进来的时候, 插槽slot就能接收到这个信息. slot插槽大大的扩展子组件的功能。
1. vant有赞ui库中slot的例子#
<van-nav-bar title="标题" left-text="返回" left-arrow>
<p slot="right">
<van-icon name="search" size="18" />
</p>
</van-nav-bar>
2. 普通插槽#
// 父组件demo.vue代码
<template>
<div>
<h3>父组件</h3>
<hr>
<Son><button>按钮</button></Son>
</div>
</template>
<script>
import Son from "./Son";
export default {
components: {
Son,
}
};
</script>
// 子组件Son.vue
<template>
<div>
<slot></slot>
</div>
</template>
3. 具名插槽#
// father.vue代码
<template>
<div>
<h3>这是父组件</h3>
<Child>
<header slot="header" style="background: yellow">这是头部</header>
<footer slot="footer" style="background: green;">这是底部</footer>
<div style="border:1px solid;">
<button>a</button>
<button>b</button>
<button>c</button>
<button>d</button>
</div>
</Child>
</div>
</template>
<script>
import Child from "@/components/Child";
export default {
components: {
Child
}
};
</script>
接收父组件带 slot="footer" 的内容
接收不带slot="xxx" 的内容
// Child.vue代码
<template>
<div style="margin-top: 30px;background: gray;height: 200px;">
<h5>这是子组件</h5>
<!--接收父组件带 slot="header" 的内容-->
<slot name="header"></slot>
<!--接收父组件带 slot="footer" 的内容-->
<slot name="footer"></slot>
<!--接收剩余内容-->
<slot></slot>
</div>
</template>
自定义组件
// demo.vue
<template>
<div>
<NavBar title="首页" @click-left="clickLeft" @click-right="clickRight"></NavBar>
</div>
</template>
<script>
import NavBar from './Nav-Bar.vue'
export default {
components: {
NavBar
},
methods:{
clickLeft() {
alert('左边被点击了');
},
clickRight() {
alert('右边被点击了')
}
}
}
</script>
// Nav-Bar.vue
<template>
<div class="nav flex jc-sb pl-15 pr-15 bg-fff aic">
<p class="blue flec aic" @click="$emit('click-left')">
<van-icon name="arrow-left" />
<span>返回</span>
</p>
<p>{
{title?title:'标题'}}</p>
<slot name="right"> <span class="blue" @click="$emit('click-right')">按钮</span></slot>
</div>
</template>
<script>
export default {
props: ['title']
}
</script>
<style lang="less">
.nav {
height: 50px;
.blue {
color: #1989fa;
}
}
</style>
以vant 的导航栏组件van-nav-bar为例
知识点:
注意: router和route不是一回事
1.通过name+params传参#
// 1.配置路由的时候添加name
{
path: "detail",
name: 'product-detail',
component: () => import("@/views/order/children/detail"),
},
// 2.跳转
this.$router.push({
// 要跳转到的路由名称
name: 'product-detail',
params: { productId: '123' }
})
// 3.接收参数
this.$route.params.productId
2.动态路由传参#
// 1.配置路由
{
path: "detail/:productId",
component: () => import("@/views/product/children/detail.vue"),
},
// 2. 跳转
this.$router.push('/product/detai/22222')
<router-link to="/product/detail/333333">传参</router-link>
// 3.接收参数
created() {
let params = this.$route.params;
console.log('params',params);
},
3.通过path+query传参#
// 带查询参数,query传参会把参数拼接到地址栏,变成 /register?plan=aaa, 使用了path,参数不能通过params传递
this.$router.push({ path: '/register', query: { plan: 'aaa' }})
// 获取参数
this.$route.query;
json-server --watch db.json
// db.json
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
http://localhost:3000/posts/1
"scripts": {
"json": "json-server --watch db.json"
},
// computed
<template>
<div>
<p>姓: {
{ xing }}</p>
<p>名: {
{ ming }}</p>
<p>姓名: {
{ xingming }}</p>
<button @click="change">修改xing</button>
</div>
</template>
<script>
export default {
data() {
return {
xing: "张",
ming: "无忌",
};
},
// 计算属性
computed: {
// xingming这个属性是由xing属性和ming计算得来
xingming() {
return this.xing + this.ming;
},
},
methods: {
change() {
this.xing = "李";
},
},
};
</script>
(1) 普通对象 VS vuex创建的对象#
(2) 相关概念#
// getters派生状态
// 1. 在 src/store/index.js
state: {
token: "",
username: "张三",
age: 100,
phone: "123456789",
},
getters: {
// 派生状态
str(state) {
return `我叫${state.username},我的年龄是${state.age}`
}
},
// 2. 在组件里使用
<template>
<div>
{
{str}}
</div>
</template>
import {mapGetters} from 'vuex';
export default {
computed:{
...mapGetters(['str'])
}
}
// action 修改状态(异步)
import Vue from "vue";
import Vuex from "vuex";
import $http from '@/utils/http';
// 导入持久化插件
import createPersistedState from "vuex-persistedstate";
Vue.use(Vuex);
// 创建仓库
const store = new Vuex.Store({
plugins: [createPersistedState()],
// 1.定义状态
state: {
token: "",
phone: "123456789",
username: "张三",
age: 100,
},
getters: {
// 派生状态
str(state) {
return `我叫${state.username},我的年龄是${state.age}`
}
},
// 2.定义mutaion
mutations: {
// 修改token
set_token(state,payload) {
state.token = payload
},
// 修改phone的状态
set_phone(state, payload) {
state.phone = payload;
},
/**
* 定义修改username的muation
* @param {*} state 状态
* @param {*} payload 传入的新数据
*/
set_username(state, payload) {
state.username = payload;
},
// 定义修改age的mutation
set_age(state, payload) {
state.age = payload;
},
},
// 3.定义action
actions: {
LOGOUT(store,payload) {
$http.post('/user/logout').then(res=> {
// 清除token和phone
store.commit('set_token','');
store.commit('set_phone','');
})
}
}
});
export default store;
// 4.退出登录时派发action
<p class="red" @click="logout2">退出登录</p>
methods: {
logout2() {
this.$store.dispatch('LOGOUT');
this.$router.push('/my');
},
}
// 模块化
// 1.定义模块的state getters mutaions actions
// src/store/modules/cart.js
export default {
state: {
cartNum: 100
},
getters: { },
mutaions: { },
actions: {}
}
// src/store/modules/type.js
export default {
state: {
aaa: 333
},
getters: { },
mutaions: { },
actions: {}
}
// 2.合并模块
import cart from './modules/cart';
const store = new Vuex.Store({
modules:{
cart,
type,
},
}
// 3.使用(在任何一个组件内)
<template>
<div>
{
{ $store.state.cart.cartNum }}
{
{$store.state.type.aaa}}
</div>
</template>
(3) vuex应用#
npm i vuex --save
// 1. src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
// 创建仓库
const store = new Vuex.Store({
});
export default store;
// 2. 挂载到根实例 /src/main.js
import router from "./router/index";
import store from './store/index';
Vue.use(Vant);
Vue.config.productionTip = false;
new Vue({
store,
router,
render: (h) => h(App),
}).$mount("#app");
const store = new Vuex.Store({
// 定义状态
state: {
username: "张三",
age: 100,
},
});
this.$store.state.username
<template>
<div>
<p>username: {
{$store.state.username}}</p>
</div>
</template>
<script>
export default {
created() {
console.log(this.$store.state);
}
};
</script>
<template>
<div>
<p>username: {
{username}}</p>
<p>age: {
{age}}</p>
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
computed: {
...mapState(['username','age'])
}
};
</script>
// 1.定义mutation
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
// 创建仓库
const store = new Vuex.Store({
// 定义状态
state: {
username: "张三",
age: 100,
},
// 定义mutaion
mutations: {
/**
* 定义修改username的muation
* @param {*} state 状态
* @param {*} payload 传入的新数据
*/
set_username(state,payload) {
state.username = payload;
},
// 定义修改age的mutation
set_age(state,payload) {
state.age = payload;
}
}
});
export default store;
// 2. 提交mutaion
<template>
<div>
<p>username: {
{$store.state.username}}</p>
<button @click="change">修改状态</button>
</div>
</template>
<script>
export default {
methods: {
change() {
// 提交mutation,参数1 mutation的名称, 参数2 新的数据
this.$store.commit('set_username','李四');
}
}
};
</script>
项目应用
vuex持久化
npm i vuex-persistedstate -S
import Vue from "vue";
import Vuex from "vuex";
// 导入持久化插件
import createPersistedState from "vuex-persistedstate";
Vue.use(Vuex);
an
const store = new Vuex.Store({
plugins: [createPersistedState()],
})
(1) 对比
(2) 操作
_js_-_cookie_
// 存储数据
localStorage.setItem(key,value); // 比如:localStorage.setItem('username','张三')
// 获取数据
localStorage.getItem(key); // 比如: localStorage.getItem('username');
// 清除数据
localStorage.clear();
相同点: 两者都是用来识别用户的
项目应用
// 1. 在vuex里定义token状态和相关的mutation
state: {
token: "",
username: "张三",
age: 100,
phone: "123456789",
},
// 定义mutaion
mutations: {
// 修改token
set_token(state,payload) {
state.token = payload
},
}
// 2. 在登录成功的时候, 把token存入vuex
$http.post('/user/login',data).then(res=> {
// 把手机号码存入store, 修改phone状态
this.$store.commit('set_phone',this.phone);
// 把token存入store
this.$store.commit('set_token',res.result.token);
// 从哪里来回哪里去
this.$router.go(-1);
})
// 3. 在axios的拦截器里, 把token放入请求头, 这样, 每次发请求的时候, 都会自动带上token
import axios from "axios";
import Vue from "vue";
import { Toast } from "vant";
// 导入store
import store from '@/store/index';
Vue.use(Toast);
// request 对请求进行拦截
service.interceptors.request.use(
(config) => {
// 获取token
let token = store.state.token;
// 开启loading
Toast.loading({
message: "加载中...",
forbidClick: true,
loadingType: "spinner",
});
// 请求头添加token
config.headers["user-token"] = token;
return config;
},
(error) => {
Promise.reject(error);
}
);
作用: 格式化数据
// 组件内的过滤器
<template>
<div>
{
{num | f}}
</div>
</template>
<script>
export default {
data() {
return {
num: 10
}
},
filters: {
f(num) {
return Number(num).toFixed(2);
}
}
}
</script>
// 全局过滤器
Vue.filter('fMoney', (money)=> {
let num = money/100;
return num.toFixed(2);
})
new Vue({})
// 定义好全局过滤器后, 组件内可以直接使用
<template>
<div>
{
{num | fMoney}}
</div>
</template>
<script>
export default {
data() {
return {
num: 1000
}
},
}
</script>
(1) 微信支付流程#
(2) 获取支付结果的两种方式#
获取支付结果, 可以使用轮询或者websocket
// 轮询
<template>
<div class="payment pay"></div>
</template>
<script>
export default {
data() {
return {
timer: null,
orderId: 'sdfasdfasdfasdfasdfasdfas'
};
},
created() {
this.waitResult();
},
beforeDestroy() {
// 销毁定时器
clearInterval(this.timer);
},
methods: {
async waitResult() {
// 创建定时器
this.timer = setInterval(async () => {
let res = await this.$axios.post("/order/detail", {
orderId: this.orderId,
});
if (res.result.orderStatus === "01") {
clearInterval(this.timer);
// 支付成功, 返回首页
this.$router.push("/");
}
}, 2000);
},
},
};
</script>
// webSocket
<template>
<div>{
{result}}</div>
</template>
// webSocket
<template>
<div>{
{result}}</div>
</template>
<script>
export default {
data() {
return {
result: ''
}
},
created() {
this.connect();
},
methods: {
connect() {
this.result = '等待支付结果...';
// 跟后端建立连接
var ws = new WebSocket("ws://huruqing.cn:3003/socket");
// onopen连接结果
ws.onopen = () => {
console.log("连接成功");
};
// 等待后端推送信息
ws.onmessage = (res) => {
this.result = res.data;
};
},
},
};
</script>
解决办法
// router/index.js
const routes = [...];
const router = new Router({
mode: "history",
scrollBehavior: () => ({
y: 0
}),
routes
});
问题: 用户从列表的第3页, 点击某个商品进入了商品详情, 当用户点击返回的时候, 默认会返回到列表页的第一页而不是第3页, 这样的体验很不好, 所以我们希望可以回到列表页的原来位置, 这样的用户体验会比较好. 分析: 之所以会回到第一页, 是因为返回到列表页的时候, 组件会重新创建, 从新执行created方法, 所以页面页重新渲染 解决: 使用keep-alive可以缓存组件的状态, 具体做法: (1) 对列表页使用keep-alive, 使其即使离开了组件, 也不会销毁 组件挂载完毕的时候绑定滚动事件, 记录滚动的位置 (2) 从详情页返回的时候, 滚动的原来的位置(在activated生命周期) **注: **
// 方法1 APP.vue
<template>
<div id="app">
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>
// 方法2, 给路由配置keepAlive属性
// (1) /router/index.js
{
path: "/product",
component: () => import("@/views/product/index.vue"),
redirect: "/product/list",
children: [
{
path: "list",
// 缓存次组件
meta: {
keepAlive: true,
tittle: '列表'
},
component: () => import("@/views/product/children/list2.vue"),
},
{
path: "detail/:productId",
component: () => import("@/views/product/children/detail.vue"),
},
],
},
// APP.vue
<template>
<div id="app">
<!-- 渲染需要缓存的组件 -->
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 渲染不需要缓存的组件 -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
// 上面需求的实现
(1) 在mounted绑定window.scroll事件, 滚动的时候保存滚动条的位置
(2) 返回时候, 重新滚动到原来保存的位置
mounted() {
window.addEventListener('scroll',()=>{
// 保存滚动条位置
if (window.scrollY>0) {
this.scrollHeight = window.scrollY;
}
},false);
},
// 进入组件
activated() {
// 滚动到最初的位置
setTimeout(()=> {
window.scrollTo(0,this.scrollHeight);
},0)
},
项目开发的时候, 一般会有多个环境, 比如开发环境, 测试环境, 生产环境, 我们调用接口的时候, 不同环境调用不同的接口, 所以要配置环境, ,方便访问。
// utils/http.js 核心代码
let env = process.env.NODE_ENV;
let baseURL;
// 开发环境
if (env === "development") {
baseURL = "http://localhost:3003";
} else {
baseURL = "http://huruqing.cn:3003";
}
const service = axios.create({
// 如果换了新的项目, 需要更换为新的接口地址
baseURL: baseURL,
timeout: 50000, // 请求超时时间(因为需要调试后台,所以设置得比较大)
});
(1) 元素单位有哪些:#
(2) rem和根标签字体大小的关系#
// rem例子 demo1.html
<!DOCTYPE html>
<html lang="en" style="font-size: 100px;">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
div{
width: 1rem;
height: 1rem;
background-color: gray;
}
</style>
</head>
<body>
<div>
</div>
</body>
</html>
// rem例子 demo1.html
<!DOCTYPE html>
<html lang="en" style="font-size: 112px;">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
div{
width: 1rem;
height: 1rem;
background-color: green;
}
</style>
</head>
<body>
<div>
</div>
</body>
</html>
(3) 移动端rem适配原理#
(4) vue项目配置rem#
npm i amfe-flexible --save
import 'amfe-flexible'
npm i [email protected]
const pxtorem = require("postcss-pxtorem");
module.exports = {
css: {
loaderOptions: {
// 后处理器配置
postcss: {
plugins: [
// 把px转为rem
pxtorem({
rootValue: 37.5,
propList: ["*"]
})
]
}
}
}
};
mixin 其实是一个对象,里面的结构大致跟普通组件的 script 里面的一样,有 data 属性,钩子函数和方法等 混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
1.组件内混入#
(1) 混入对象的生命周期先执行 (2) data里的状态若有重名, 取的是组件里的状态
// mixin.js
export default {
data: function() {
return {
username: "huruqing",
age: 100
};
},
created() {
console.log('这是混入对象')
},
methods: {
say() {
console.log('hahahhahahha');
}
}
};
// demo.vue
<template>
<div>
<p>{
{username}}</p>
<p>{
{msg}}</p>
<p>{
{age}}</p>
</div>
</template>
<script>
import mixin from './mixin'
export default {
mixins:[mixin],
data() {
return {
username: '张三',
msg: 'hahahahahahha'
}
},
created() {
console.log('组件的created');
this.say();
}
}
</script>
2.全局混入#
// mixin.js
export default {
methods: {
loadingStart() {
this.$toast.loading({
message: '加载中...',
forbidClick: true,
duration:0
});
},
loadingFinish() {
this.$toast.clear();
}
}
}
// main.js,这个代码放在Vue.use(Vant)之后
import mixin from '@/utils/mixin';
Vue.mixin(mixin);
// 其他组件就可以直接使用下面代码来显示loading
this.loadingStart();
<template>
<div>
<input type="text" v-model="obj.username" />
<p>{
{ obj.username }}</p>
</div>
</template>
<script>
export default {
data: function () {
return {
obj: {
username: "张三",
},
};
},
watch: {
obj: {
// 发生改变时执行的函数
handler(newObj) {
console.log(newObj.username);
},
// 首次绑定watch就执行
immediate: true,
// 深层监控,不设置,引用数据类型监控不到
deep: true
}
},
};
</script>
// demo.vue
<template>
<div>
<!-- 不传参数 -->
<Son/>
<!-- 传了一个字符串 -->
<!-- <Son :msg="'他是张三'" /> -->
<!-- 传了一串数字 -->
<!-- <Son :msg="22222"/> -->
</div>
</template>
<script>
import Son from "./Son.vue";
export default {
components: {
Son,
}
};
</script>
// Son.vue
<template>
<div>{
{msg}}</div>
</template>
<script>
export default {
// props: ['msg']
props:{
msg: {
type:String,
default: 'hello'
}
}
}
</script>
<template>
<div>
<span ref="demo">ref例子</span>
<button @click="handleClick">点击</button>
<hr />
<Son ref="son" />
</div>
</template>
<script>
import Son from "./Son.vue";
export default {
components: {
Son,
},
methods: {
handleClick() {
console.log(this.$refs.demo.innerText);
console.log(this.$refs.son.msg);
},
},
};
</script>
// Son.vue
<template>
<div>
{
{msg}}
</div>
</template>
<script>
export default {
data() {
return {
msg: 'hello',
title: '2222222'
}
}
}
</script>
// 父组件控制子组件的显示和隐藏(子组件无状态)
// demo.vue
<template>
<div>
<button @click="show = !show">点击</button>
<hr>
<Son :show="show" />
</div>
</template>
<script>
import Son from "./Son.vue";
export default {
components: {
Son,
},
data() {
return {
show: true,
};
},
};
</script>
// Son.vue
<template>
<div v-if="show">
<p>子组件内容</p>
<p>子组件内容</p>
<p>子组件内容</p>
<p>子组件内容</p>
</div>
</template>
<script>
export default {
props: ['show']
}
</script>
// 父组件控制子组件的显示和隐藏(子组件有状态)
<template>
<div>
<button @click="$refs.aaa.show=!$refs.aaa.show">显示弹窗</button>
<Alert ref="aaa"/>
</div>
</template>
<script>
import Alert from './Alert.vue'
export default {
components: {
Alert
},
};
</script>
// Son.vue(假设子组件是别人设计的组件, 多处地方在使用, 所以并不适宜去改动, 不然容易改出bug, 子组件有个show的状态来控制其显示和隐藏
<template>
<div v-if="show">
<p>{
{msg}}</p>
<p>{
{msg}}</p>
<p>{
{msg}}</p>
</div>
</template>
<script>
export default {
data() {
return {
show: true,
msg: 'hello vue'
}
}
}
</script>
修改了数据之后, dom节点并不会立马更新, dom节点的更新是异步的, 想要拿到更新后的dom需要使用nextStick
<template>
<div>
<li ref="aa">{
{ count1 }}</li>
<li ref="bb">{
{ count2 }}</li>
<li ref="cc">{
{ count3 }}</li>
<button @click="handleClick">修改数据</button>
</div>
</template>
<script>
export default {
data() {
return {
count1: 0,
count2: 0,
count3: 0,
};
},
methods: {
handleClick() {
this.count1 = 1;
// this.count1=1;执行后dom并不会立即更新,dom节点的更新是异步的
console.log(this.$refs.aa.innerHTML); // 0
// 当dom节点更新完毕, 会立即调用nextStick里的回调函数
this.$nextTick(() => {
console.log(this.$refs.aa.innerHTML);
});
this.count2 = 2;
this.count3 = 3;
},
},
};
</script>
// 1. 在根目录新建mock文件夹
// 2. 添加/category/all.json和 /product/getBanners.json, json的数据就根据接口文档进行模拟
// 3. vue.config.js里配置
devServer: {
// 代理
proxy: {
// 只要请求地址有'api'都会匹配上
"/api": {
target: "http://81.71.65.4:3003",
ws: true,
// 允许跨域
changeOrigin: true,
pathRewrite: {
"^/api": "", //通过pathRewrite重写地址,将前缀/api转为/
},
},
},
before(app) {
// 模拟接口数据, 前面都加上了api是为了跨域设置的需要
// 分类列表
app.get("/api/category/all", (req, res) => {
res.json(require('./mock/category/all.json'));
});
// banner列表
app.get("/api/product/getBanners", (req, res) => {
res.json(require('./mock/product/getBanners.json'));
});
},
},
文章浏览阅读1.3k次,点赞40次,收藏19次。虽然你不能直接计算每个房间的人数,但通过马尔科夫链的蒙特卡洛方法,你可以从任意状态(房间)开始采样,并最终收敛到目标分布(人数分布)。然后,根据一个规则(假设转移概率是基于房间的人数,人数较多的房间具有较高的转移概率),你随机选择一个相邻的房间作为下一个状态。比如在巨大城堡,里面有很多房间,找到每个房间里的人数分布情况(每个房间被访问的次数),但是你不能一次进入所有的房间并计数。但是,当你重复这个过程很多次时,你会发现你更有可能停留在人数更多的房间,而在人数较少的房间停留的次数较少。_马尔科夫链期望怎么求
文章浏览阅读3.9k次。一、su命令su命令用于切换当前用户身份到其他用户身份,变更时须输入所要变更的用户帐号与密码。命令su的格式为:su [-] username1、后面可以跟 ‘-‘ 也可以不跟,普通用户su不加username时就是切换到root用户,当然root用户同样可以su到普通用户。 ‘-‘ 这个字符的作用是,加上后会初始化当前用户的各种环境变量。下面看下加‘-’和不加‘-’的区别:root用户切换到普通..._限制su root登陆
文章浏览阅读1.2k次。精通VC与Matlab联合编程(六)作者:邓科下载源代码浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程 Matlab C/C++函数库是Matlab扩展功能重要的组成部分,包含了大量的用C/C++语言重新编写的Matlab函数,主要包括初等数学函数、线形代数函数、矩阵操作函数、数值计算函数_精通vc和matlab联合编程 六
文章浏览阅读128次。在MVC2中默认并没有实现DescriptionAttribute(虽然可以找到这个属性,通过阅读MVC源码,发现并没有实现方法),这很不方便,特别是我们使用EditorForModel的时候,我们需要对字段进行简要的介绍,下面来扩展这个属性。新建类 DescriptionMetadataProvider然后重写DataAnnotationsModelMetadataPro..._asp.net mvc 模型description
文章浏览阅读1.3k次。一.概述 本篇继续探讨web应用架构,讲基于DDD风格下最初的领域模型架构,不同于DDD风格下CQRS架构,二者架构主要区别是领域层的变化。 架构的演变是从领域模型到C..._eshoponweb
文章浏览阅读2.6w次,点赞23次,收藏85次。首先说明,本人之前没用过zookeeper、kafka等,尚硅谷十几个小时的教程实在没有耐心看,现在我也不知道分区、副本之类的概念。用kafka只是听说他比RabbitMQ快,我也是昨天晚上刚使用,下文中若有讲错的地方或者我的理解与它的本质有偏差的地方请包涵。此文背景的环境是windows,linux流程也差不多。 官网下载kafka,选择Binary downloads Apache Kafka 解压在D盘下或者什么地方,注意不要放在桌面等绝对路径太长的地方 打开conf_springboot kafka
文章浏览阅读1k次。编好水晶报表代码,用的是ActiveX模式,在本机运行,第一次运行提示安装ActiveX控件,安装后,一切正常,能正常打印,但发布到网站那边运行,可能是一闪而过,连提示安装ActiveX控件也没有,甚至相关的功能图标都不能正常显示,再点"打印图标"也是没反应解决方法是: 1.先下载"PrintControl.cab" http://support.businessobjects.c_水晶报表 不能打印
文章浏览阅读1.3k次。绝大部分UC/OS-II的源码是用移植性很强的ANSI C写的。也就是说某产品可以只使用很少几个UC/OS-II调用,而另一个产品则使用了几乎所有UC/OS-II的功能,这样可以减少产品中的UC/OS-II所需的存储器空间(RAM和ROM)。UC/OS-II是为嵌入式应用而设计的,这就意味着,只要用户有固化手段(C编译、连接、下载和固化), UC/OS-II可以嵌入到用户的产品中成为产品的一部分。1998年uC/OS-II,目前的版本uC/OS -II V2.61,2.72。1.UC/OS-Ⅱ简介。_ucos
文章浏览阅读614次,点赞22次,收藏11次。大家好,本文将围绕python自动化运维需要掌握的技能展开说明,python自动化运维从入门到精通是一个很多人都想弄明白的事情,想搞清楚python自动化运维快速入门 pdf需要先了解以下几个事情。这篇文章主要介绍了一个有趣的事情,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。_运维学python该学些什么
文章浏览阅读524次。2019独角兽企业重金招聘Python工程师标准>>> ..._hotfix for msxml 4.0 service pack 2 - kb832414
文章浏览阅读546次。python和易语言的脚本哪门更实用?_易语言还是python适合辅助
文章浏览阅读134次。详解redis中的锁以及使用场景,指令,事务,分布式,命令,时间详解redis中的锁以及使用场景易采站长站,站长之家为您整理了详解redis中的锁以及使用场景的相关内容。分布式锁什么是分布式锁?分布式锁是控制分布式系统之间同步访问共享资源的一种方式。为什么要使用分布式锁? 为了保证共享资源的数据一致性。什么场景下使用分布式锁? 数据重要且要保证一致性如何实现分布式锁?主要介绍使用redis来实..._redis setnx watch