安装Vue
局部安装
局部安装并使用vue-cli 4.x版本,和创建项目
1 | # 先创建一个文件夹 |
全局安装
1 | npm install -g @vue/cli |
1 | # 安装脚手架 |
安装Element-UI
全局安装
1 | # 安装 |
1 | // main.js 使用 |
按需引入
1 | # 安装 |
1 | // main.js |
如果没有找到.babelirc文件,找找babel.config.js文件
一个一个import 按需引入有点麻烦,在根目录下面创建一个plugins文件夹,在这个文件夹下面创建element.js
1 | import Vue from 'vue' |
在main.js引入element.js
1 | import '../element.js' |
安装CSS预处理器
Sass
安装的是sass,使用的时候是scss…. 留意
1 | npm install --save-dev node-sass |
1 | # 注意这里是scss |
Less
1 | npm i less less-loader --save-dev |
1 | <style scoped lang="less"> |
重置样式
下面的代码可以搜索reset.css
在src/assets 下创建css文件夹,在这个文件下创建reset.css文件,粘贴
1 | /* http://meyerweb.com/eric/tools/css/reset/ |
在App.vue或者其他的组件中使用
1 | <style lang="scss"> |
安装图标库
1 | # 安装 |
安装axios
1 | npm i axios -S |
安装vue-router
1 | # vue-router3 和 4 的配置不一样 |
创建文件和文件夹
src->router->index.js
1 | import Vue from 'vue' |
路由懒加载和异步组件
1 | export default new Router({ |
setToken封装
src→utils→settoken.js
1 | export function setToken(key,token){ |
使用
1 | <script> |
配置代理服务器
1 | const { defineConfig } = require('@vue/cli-service') |
404
1 | { |
相关推荐

2022-11-19
Vue
按照官方文档的教程步骤来,大部分的代码Demo,都是通过脚手架创建的项目的基础上创建的,用的版本的Vue3,Typescript,组合式的写法 基础创建一个应用多个应用实例 没什么用,现在项目都是从头开始都是vue项目,不会用来一步一步替换,没有想到应用场景 1234567891011121314151617181920212223242526272829303132333435363738394041424344<!DOCTYPE html><html><head> <title>Vue Multiple Instances Example</title> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script></head><body> <div id="app1"> <p>{{ message }}</p> <button @click="updateMessage">更新消息</button> </div> <div id="app2"> <p>{{ message }}</p> <button @click="updateMessage">更新消息</button> </div> <script> var app1 = new Vue({ el: '#app1', data: { message: '这是第一个 Vue 实例的消息' }, methods: { updateMessage() { this.message = '第一个实例的消息已更新'; } } }); var app2 = new Vue({ el: '#app2', data: { message: '这是第二个 Vue 实例的消息' }, methods: { updateMessage() { this.message = '第二个实例的消息已更新'; } } }); </script></body></html> 模板语法文本插值 双大括号标签会被替换为msg 属性的值。同时每次 msg 属性更改时它也会同步更新。 12345678<script setup lang="ts">import {ref} from "vue";const text = ref<string>("文本插值语法");</script><template> {{text}}</template> 原始 HTML 有的时候想想渲染源码,有的时候不想渲染源码 v-html就是指令语法 123456789<script setup lang="ts">import {ref} from "vue";const rawHtml = ref<string>("<span style='color: red'>This should be red.</span>");</script><template> <p>Using text interpolation: {{ rawHtml }}</p> <p>Using v-html directive: <span v-html="rawHtml"></span></p></template> Attribute 绑定 如果想给html的属性绑定数据要怎么操作呢,下面以给div的id和class属性绑定做演示 123456789101112131415161718192021222324252627282930313233343536373839404142<script setup lang="ts">import {ref} from "vue";const myId = ref<string>("myId");const showButton = ref<boolean>(false); type objectOfAttrs={ id: string, class:string} const objectOfAttrsObj=ref<objectOfAttrs>({ id: "myId4", class:"demo"}); </script><template> <!-- ❎错误做法 --> <div id={{myId}}></div> <!-- ✅正确做法,如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。 --> <div v-bind:id="myId"></div> <!-- ✅正确做法,简写写法 --> <div :id="myId"></div> <!-- ✅正确做法,同名简写写法,就是属性(Id),和等号对应的值是一样的话 --> <div :id></div> <!-- ✅正确做法,同名简写写法,第二种写法 --> <div v-bind:id></div> <!-- -------------------------------------------------------- --> <!-- 绑定布尔类型 --> <button :disabled="showButton">按钮</button> <!-- 动态绑定多个值 --> <div v-bind="objectOfAttrsObj">动态绑定多个值,只是需要写v-bind</div></template> 响应式基础这个有点底层,不去了解了,大概意思是简单的数据类型就用ref,对象或者复杂嵌套的结构就用reactive 计算属性基础示例 Vue 的计算属性会自动追踪响应式依赖。它会检测到 authorComputed 依赖于 author.books,所以当 author.books 改变时,任何依赖于 authorComputed 的绑定都会同时更新。 计算属性会被缓存,并且只调用一次,方法是调用一次执行一次,在例子中,触发了一次页面渲染(页面的数据有变动),方法就会被执行一次 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061<script setup lang="ts">import {computed, reactive, ref} from "vue";type authorType={ name:string, books:string[]}const author = reactive<authorType>({ name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ]})// 计算属性,使用泛型,返回值必须是字符串const authorComputed = computed<string>(()=>{ return author.books.length >0?author.books.length.toString():"没有书"})function add(){ author.books.push("Vue 5 - Advanced Guide")}// 计算属性,使用泛型,返回值必须是字符串const myDateTimeComputed = computed<number>(() => { return getDateTime();});function getDateTime(){ console.log("方法被调用") return Date.now();}function myDateTimeMethod(){ return getDateTime();}// 定义一个用于触发重新渲染的状态const renderCounter = ref(0);function forceRerender() { console.log("12321") renderCounter.value++;}</script><template> <!-- 计算属性 --> <span>通过计算属性计算出来的结果:{{ authorComputed }}</span> <br> <button @click="add()">添加数据</button> <br> <!-- 计算属性和方法的区别 --> <button @click="forceRerender">触发重新渲染</button> 计算属性和方法的区别-计算属性:{{ myDateTimeComputed }} 计算属性和方法的区别-方法:{{renderCounter}}-{{ myDateTimeMethod() }}</template> 可写计算属性 计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建 1234567891011121314151617181920212223242526272829303132333435363738394041<script setup lang="ts">import {computed, reactive, ref} from "vue";const firstName = ref('Anthony')/** * 错误的写法 */// const fullName = computed(()=>{// return firstName.value + ' ' + lastName.value// })/** * 正确的写法 */const fullName = computed({ // getter get() { return firstName.value }, // setter set(newValue) { // 注意:我们这里使用的是解构赋值语法 firstName.value = newValue }})/** * 这样是不对的 */function showWarn(){ console.log("修改计算属性") fullName.value="DiDiDi"}</script><template> 演示修改计算属性,控制台报错:{{fullName}} <button @click="showWarn">尝试修改计算属性</button></template> Class 与 Style 绑定太麻烦了,不看了 条件渲染v-if 可以单独使用 v-else-if 要跟v-if 一起使用 v-else 要跟v-if 或者 v-else-if 一起使用 12345678910111213<script setup lang="ts">import {computed, reactive, ref} from "vue";const season = ref<number>(6);</script><template> <h1 v-if="season >=1 && season <=3">春季</h1> <h1 v-else-if="season >=4 && season <=6">不是春季</h1> <h1 v-else>数据错误</h1></template> 列表渲染123456789101112131415161718192021222324<script setup lang="ts">import {computed, reactive, ref} from "vue";const items = ref([{ message: 'Foo' }, { message: 'Bar' }])</script><template> for循环 <li v-for="(item,index) in items"> {{index}}-{{ item.message }} </li> 解构函数 <li v-for="{ message } in items"> {{ message }} </li> 解构函数,有索引的时候 <li v-for="({message},index) in items"> {{index}}-{{ message }} </li></template> 事件处理我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler" 或 @click="handler"。 内联事件处理器 12345678910<script setup lang="ts">import {computed, reactive, ref} from "vue";const count = ref(0)</script><template> <button @click="count++">Add 1</button> <p>Count is: {{ count }}</p></template> 方法事件处理器 1234567891011<script setup lang="ts">function greet() { console.log("方法事件处理器")}</script><template> <!-- `greet` 是上面定义过的方法名 --> <button @click="greet">Greet</button></template> 表单输入绑定主要是看框架了,先不学了,太多细节了 生命周期钩子这个API好多个,以后慢慢看 侦听器每次修改被监听的对象,就会打印旧值和新值 基本示例 12345678910111213141516<script setup lang="ts">import {ref, watch} from 'vue'/*被监听的对象*/const question = ref<number>(1);// 可以直接侦听一个 refwatch(question, async (newQuestion, oldQuestion) => { console.log("老值:", oldQuestion) console.log("新值:", newQuestion)})</script><template> <input v-model="question"/></template> 侦听不同的数据源类型 watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455<script setup lang="ts">import {reactive, ref, watch} from 'vue'const x = ref<number>(0)const y = ref<number>(0)type authorType={ name: string,}const z = reactive<authorType>({ name:"anthony"})// refwatch(x, (newX,oldValue) => { console.log(`监听单个ref,x的旧值是:${oldValue},新值是:${newX}`)})// getter 函数watch( () => x.value + y.value, (newSum, oldSum) => { console.log(`监听getter函数, 原来的和值是:${oldSum},新值是: ${newSum}`) })// 多个来源组成的数组watch([x, () => y.value], ([newX, newY],[oldX, oldY]) => { console.log(`监听多个数据源:X的旧值是:${oldX},X的新值是:${newX},Y的旧值是:${oldY},Y的新值是:${newY}`)})// 监听reactive// 错误,因为 watch() 得到的参数是一个 number// 错误的写法,会提示报错,// MyClick.vue:35 [Vue warn]: Invalid watch source: anthony A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.// at <MyClick>// at <App>// watch(z.name, (count) => {// console.log(`name is: ${count}`)// })// 正确的写法watch( () => z.name, (nameNew,oldName) => { console.log(`name is: ${nameNew},${oldName}`) })</script><template> <input v-model="x" type="number"/> <input v-model="y" type="number"/> <input v-model="z.name" /></template> 模板引用进入到页面会自动聚焦到输入框中 123456789101112131415<script setup>import { ref, onMounted } from 'vue'// 声明一个 ref 来存放该元素的引用// 必须和模板里的 ref 同名const input = ref(null)onMounted(() => { input.value.focus()})</script><template> <input ref="input" /></template> 组件基础定义组件 123456789<script setup>import { ref } from 'vue'const count = ref(0)</script><template> <button @click="count++">You clicked me {{ count }} times.</button></template> 使用组件 在父组件中引入 1234567<script setup lang="ts">import MyClick from "@/components/MyClick.vue";</script><template> <MyClick/></template> 传递 props(父传子) 1234567891011121314151617181920212223// 子组件<script setup lang="ts">import {ref} from 'vue'const count = ref<number>(0)defineProps(['title'])</script><template> <button @click="count++">{{title}},You clicked me {{ count }} times.</button></template>// 父组件<script setup lang="ts">import MyClick from "@/components/MyClick.vue";</script><template> <MyClick title="计算器1"/> <MyClick title="计算器2"/> <MyClick title="计算器3"/> <MyClick title="计算器4"/></template> emit(子传父) 父组件 123456789101112131415161718192021222324<script setup lang="ts">import { ref } from 'vue'import MyEmit from "@/components/MyEmit.vue";type Person = { name: string, age: number}const myName = ref<string>('')const myAge = ref<number>('')const getSubmit = (data: Person) => { myName.value = data.name myAge.value = data.age}</script><template> <MyEmit @myEmit="getSubmit" /> 从子组件接收的数据:{{ myName }} {{ myAge }}</template> 子组件 123456789101112131415<script setup lang="ts">type Person = { name: string, age: number}const me = { name: 'anthony', age: 23}const emit = defineEmits<{ (e: 'myEmit', payload: Person): void }>();emit('myEmit', me)</script> $bus 消息总线main.js 123456789101112131415//引入Vueimport Vue from 'vue'//引入Appimport App from './App.vue'//关闭Vue的生产提示Vue.config.productionTip = false//创建vmnew Vue({ el:'#app', render: h => h(App), beforeCreate() { Vue.prototype.$bus = this //安装全局事件总线 },}) App.vue 1234567891011121314151617181920212223242526272829<template> <div class="app"> <h1>{{msg}}</h1> <School/> <Student/> </div></template><script> import Student from './components/Student' import School from './components/School' export default { name:'App', components:{School,Student}, data() { return { msg:'你好啊!', } } }</script><style scoped> .app{ background-color: gray; padding: 5px; }</style> Student.vue 12345678910111213141516171819202122232425262728293031323334<template> <div class="school"> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div></template><script> export default { name:'School', data() { return { name:'尚硅谷', address:'北京', } }, mounted() { // console.log('School',this) this.$bus.$on('hello',(data)=>{ console.log('我是School组件,收到了数据',data) }) }, beforeDestroy() { this.$bus.$off('hello') }, }</script><style scoped> .school{ background-color: skyblue; padding: 5px; }</style> School.vue 1234567891011121314151617181920212223242526272829303132<template> <div class="student"> <h2>学生姓名:{{name}}</h2> <h2>学生性别:{{sex}}</h2> <button @click="sendStudentName">把学生名给School组件</button> </div></template><script> export default { name:'Student', data() { return { name:'张三', sex:'男', } }, methods: { sendStudentName(){ this.$bus.$emit('hello',this.name) } }, }</script><style lang="less" scoped> .student{ background-color: pink; padding: 5px; margin-top: 30px; }</style> $set$nextTick深入组件插槽插槽内容与出口 主文件 1234567891011121314151617181920212223242526272829<script setup lang="ts">import { ref, provide, reactive } from 'vue'import First from "@/components/First.vue";import MySlotWithName from "@/components/MySlotWithName.vue";import MySlotWithOutName from "@/components/MySlotWithOutName.vue";</script><template> <h1>插槽演示</h1> <!-- 匿名插槽 --> <MySlotWithOutName> <a href="https://baidu.com">跳转到baidu</a> </MySlotWithOutName> <br> <MySlotWithName> <!-- 具名插槽 --> <!-- <template v-slot:url> --> <!-- 简写的方式 --> <template #url> <a href="https://google.com">跳转到谷歌</a> </template> </MySlotWithName></template> MySlotWithOutName.vue 1234<template> 匿名插槽 <slot /></template> 1234<template> 具名插槽 <slot name="url" /></template> 作用域插槽 12345678910111213<script setup lang="ts">import MySlotWithName from "@/components/MySlotWithName.vue";</script><template> <MySlotWithName> <template #url="data"> {{ data.title }}- {{ data.age }} <a href="https://google.com">跳转到谷歌</a> </template> </MySlotWithName></template> 1234<template> 具名插槽 <slot name="url" title="anthony" age="12" /></template> 依赖注入给所有的下级组件,包括直接子组件传递数据和方法 这个例子的最上层组件修改数据之后,可以修改所有组件显示的数据 这个例子的下层组件修改数据之后,也是可以修改所有组件显示的数据 最上层组件 12345678910111213141516171819202122232425262728293031323334353637<script setup lang="ts">import { ref, provide, reactive } from 'vue'import First from "@/components/First.vue";type Person = { name: string, age: number}const me: Person = reactive({ name: 'anthony', age: 23})provide("provideDemo", me)const update = () => { me.age = me.age + 1 console.log(me);}const updateTwo = () => { me.age = me.age + 2 console.log(me);}provide("provideUpdateTwo", updateTwo)</script><template> 最顶层组件,接收到的数据:{{ me.name }},{{ me.age }}<button @click="update">修改所有层数据+1</button> <br> <First /></template> 第一层组件 1234567891011121314151617<script setup lang="ts">import { inject } from 'vue'import Second from "./Second.vue";type Person = { name: string, age: number}const me = inject<Person>("provideDemo")</script><template> 这是第一层,接收到的数据:{{ me.name }},{{ me.age }} <br> <Second /></template> 第二层组件 12345678910111213141516<script setup lang="ts">import { inject } from 'vue'import Third from "./Third.vue";type Person = { name: string, age: number}const me = inject<Person>("provideDemo")</script><template> 这是第二层,接收到的数据:{{ me.name }},{{ me.age }} <br> <Third /></template> 第三层组件 123456789101112131415<script setup lang="ts">import { inject } from 'vue'type Person = { name: string, age: number}const me = inject<Person>("provideDemo")const provideUpdateTwo = inject("provideUpdateTwo")</script><template> 这是第三层,接收到的数据:{{ me.name }},{{ me.age }}<button @click="provideUpdateTwo">修改最顶层数据+2</button></template> yarnyarn的安装 1npm install -g yarn yarn常用命令 12345678910111213141516// 初始化yarn init // 添加包yarn add [package]yarn add [package]@[version]yarn add [package]@[tag]// 添加到不同依赖项yarn add [package] --devyarn add [package] --peeryarn add [package] --optional// 升级包yarn upgrade [package]// 移除依赖包yarn remove [package]// 安装所有依赖yarn 或 yarn install 报错1.node新版本引起的报错 1234this[kHandle] = new _Hash(algorithm, xofLen);^Error: error:0308010C:digital envelope routines::unsupported 解决方法1: 123456推荐:修改package.json,在相关构建命令之前加入SET NODE_OPTIONS=--openssl-legacy-provider"scripts": { "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve", "build": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build"}, 解决方法2: 降低node版本 前端Vue父组件点击按钮打开子组件弹窗案例父组件 12345678910111213141516171819202122232425<template> <div> # 需要定义ref=child <indexChild ref="child"></indexChild> <el-button @click="open">打开弹窗</el-button> </div></template><script>import indexChild from "../../components/indexChild.vue";export default { components: { indexChild }, data () { return { }; }, methods: { open () { this.$refs.child.open(); // 这样可以直接访问子组件方法,用ref拿子组件方法 } }}</script> 子组件 123456789101112131415161718192021222324252627<template> <div> <el-dialog title="收货地址" :visible.sync="dialogFormVisible"> <span>这是一段信息</span> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">取 消</el-button> <el-button type="primary" @click="dialogFormVisible = false">确 定</el-button> </div> </el-dialog> </div></template><script>export default { data () { return { dialogFormVisible: false, }; }, methods: { open () { // 在父组件调用打开 this.dialogFormVisible = true } }};</script> 参考:前端Vue父组件点击按钮打开子组件弹窗案例

2022-11-19
Element-UI
表单验证简单版123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899<template> <div class="login"> <el-card class="box-card"> <div slot="header" class="clearfix"> <span>通用后台管理系统</span> </div> <el-form label-width="80px" :model="form" ref="form"> <el-form-item label="用户名" prop="username" :rules="[ {required:true,message:'请输入用户名',trigger:'blur'}, {min:6,max:12,message:'长度在6-12位字符',trigger:'blur'}, ]"> <el-input v-model="form.username"></el-input> </el-form-item> <el-form-item label="密码" prop="password" :rules="[ {required:true,message:'请输入密码',trigger:'blur'}, {min:6,max:12,message:'长度在6-12位字符',trigger:'blur'}, ]"> <el-input type="password" v-model="form.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="login('form')">登录</el-button> </el-form-item> </el-form> </el-card> </div></template><script>export default { data() { return { form: { username: "", password: "" } } }, methods:{ login(form){ this.$refs[form].validate((valid)=>{ if(valid){ console.log("验证通过") this.axios.post("http://localhost",this.form).then( res=>{ console.log(res) if(res.data.status === 200){ localStorage.setItem("username",res.data.username) this.$message({ message:res.data.message, type:'success' }) this.$router.push('/home') } } ) .catch(err=>{ console.error(err) }) }else { console.error("验证不通过") } }) } }}</script><style scoped lang="scss">.login { width: 100%; height: 100%; position: absolute; background: cadetblue; .box-card { width: 450px; margin: 200px auto; .el-button { width: 100%; } }}</style> 自定义校验123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119<template> <div class="login"> <el-card class="box-card"> <div slot="header" class="clearfix"> <span>通用后台管理系统</span> </div> <el-form label-width="80px" :model="form" :rules="rules" ref="form"> <el-form-item label="用户名" prop="username"> <el-input v-model="form.username"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="form.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="login('form')">登录</el-button> </el-form-item> </el-form> </el-card> </div></template><script>export default { data() { // 验证用户名 const validateName = (rule, value, callback) => { if (value === '') { callback(new Error("请输入用户名")) } else if (value === '123456') { console.log("11111111111") callback(new Error('换个用户名,猜到啦')) } else { callback() } } const validatePassword = (rule, value, callback) => { if (value === '') { callback(new Error("请输入密码")) } else if (!value === '123456') { callback(new Error('换个密码,猜到啦')) } else { callback() } } return { form: { username: "", password: "" }, rules: { username: [{validator: validateName, trigger: 'blur'}], password: [{validator: validatePassword, trigger: 'blur'}], } } }, methods: { login(form) { this.$refs[form].validate((valid) => { if (valid) { console.log("验证通过") // this.axios.post("http://localhost", this.form).then( // res => { // console.log(res) // if (res.data.status === 200) { // localStorage.setItem("username", res.data.username) // this.$message({ // message: res.data.message, // type: 'success' // }) // this.$router.push('/home') // } // } // ) // .catch(err => { // console.error(err) // }) } else { console.error("验证不通过") } }) } }}</script><style scoped lang="scss">.login { width: 100%; height: 100%; position: absolute; background: cadetblue; .box-card { width: 450px; margin: 200px auto; .el-button { width: 100%; } }}</style> 自定义校验封装新建一个vaildate.js 123456789101112131415161718192021// 用户名匹配export function nameRule(rule,value,callback){ if (value === '') { callback(new Error("请输入用户名")) } else if (value === '123456') { console.log("11111111111") callback(new Error('换个用户名,猜到啦')) } else { callback() }}export function passwordRule(rule,value,callback){ if (value === '') { callback(new Error("请输入密码")) } else if (value === '123456') { callback(new Error('换个密码,猜到啦')) } else { callback() }} 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697<template> <div class="login"> <el-card class="box-card"> <div slot="header" class="clearfix"> <span>通用后台管理系统</span> </div> <el-form label-width="80px" :model="form" :rules="rules" ref="form"> <el-form-item label="用户名" prop="username"> <el-input v-model="form.username"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="form.password"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="login('form')">登录</el-button> </el-form-item> </el-form> </el-card> </div></template><script>import {nameRule,passwordRule} from "@/utils/vaildate";export default { data() { return { form: { username: "", password: "" }, rules: { username: [{validator: nameRule, trigger: 'blur'}], password: [{validator: passwordRule, trigger: 'blur'}], } } }, methods: { login(form) { this.$refs[form].validate((valid) => { if (valid) { console.log("验证通过") // this.axios.post("http://localhost", this.form).then( // res => { // console.log(res) // if (res.data.status === 200) { // localStorage.setItem("username", res.data.username) // this.$message({ // message: res.data.message, // type: 'success' // }) // this.$router.push('/home') // } // } // ) // .catch(err => { // console.error(err) // }) } else { console.error("验证不通过") } }) } }}</script><style scoped lang="scss">.login { width: 100%; height: 100%; position: absolute; background: cadetblue; .box-card { width: 450px; margin: 200px auto; .el-button { width: 100%; } }}</style> 遍历路由渲染菜单栏src>common>menu.vue 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869<template> <div class="menu"> <el-aside width="200px"> <el-menu router default-active="2" class="el-menu-vertical-demo" background-color="cornflowerblue" text-color="#fff" active-text-color="#ffd04b"> <template v-for="(item,index) in menus"> <div> <el-submenu :index="index + '' " :key="index" v-if="!item.hidden"> <template slot="title"> <i :class="item.iconClass"></i> <span>{{ item.name }}</span> </template> <el-menu-item-group v-for="(child,index) in item.children" :key="index"> <el-menu-item :index="child.path"> <i :class="child.iconClass"></i> {{ child.name }} </el-menu-item> </el-menu-item-group> </el-submenu> </div> </template> </el-menu> </el-aside> </div></template><script>export default { data(){ return{ menus:[] } }, created() { console.log(this.$router.options.routes) this.menus=this.$router.options.routes }, methods: { }}</script><style scoped lang="scss">.menu{ .el-aside{ height: 100%; .el-menu{ height: 100%; .fa{ margin-right: 10px; } } .el-submenu .el-menu-item{ min-width: 0; } }}</style> route.js 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136import Vue from 'vue'import Router from 'vue-router'// import Home from '../components/Home.vue'Vue.use(Router)export default new Router({ routes:[ { path:'/', // 重定向 redirect:'/login', // 路由懒加载 hidden:true, component:()=>import('@/components/Login.vue') // 异步组件 }, { path:'/login', name:'Login', hidden:true, // 路由懒加载 component:()=>import('@/components/Login.vue') // 异步组件 }, { path:'/home', // component:Home hidden:true, // 路由懒加载 component:()=>import('@/components/Home.vue') // 异步组件 }, { path:'/home2', // component:Home hidden:true, // 路由懒加载 component:resolve =>require(['@/components/Home.vue'],resolve) // 异步组件 }, { path:'*', hidden:true, // 路由懒加载 component:()=>import('@/components/404.vue') }, { path:"/home", name:"学生管理", iconClass:'fa fa-user', // 默认重定向 redirect:'/home/student', component:()=>import('@/components/Home.vue'), children:[ { path:'/home/student', name:'学生列表', iconClass:"fa fa-list", component:()=>import("@/components/students/StudentList.vue") }, { path:'/home/info', name:'信息列表', iconClass:"fa fa-list", component:()=>import("@/components/students/InfoList.vue") }, { path:'/home/infos', name:'信息管理', iconClass:"fa fa-list-alt", component:()=>import("@/components/students/InfoLists.vue") }, { path:'/home/work', name:'作业列表', iconClass:"fa fa-list-ul", component:()=>import("@/components/students/WorkList.vue") }, { path:'/home/workd', name:'作业管理', iconClass:"fa fa-th-list", component:()=>import("@/components/students/WorkMent.vue") } ] }, { path:"/home", name:"数据分析", iconClass:'fa fa-bar-chart', component:()=>import('@/components/Home.vue'), children:[ { path:'/home/dataview', name:'数据概览', iconClass:"fa fa-list-alt", component:()=>import("@/components/dataAnalysis/DataView.vue") }, { path:'/home/mapview', name:'地图概览', iconClass:"fa fa-list-alt", component:()=>import("@/components/dataAnalysis/MapView.vue") }, { path:'/home/travel', name:'信息管理', iconClass:"fa fa-list-alt", component:()=>import("@/components/dataAnalysis/TraveMap.vue") }, { path:'/home/score', name:'分数地图', iconClass:"fa fa-list-alt", component:()=>import("@/components/dataAnalysis/ScoreMap.vue") } ] }, { path:"/users", name:"用户中心", iconClass:'fa fa-user', component:()=>import('@/components/Home.vue'), children:[ { path:'/users/user', name:'权限管理', iconClass:"fa fa-user", component:()=>import("@/components/users/User.vue") } ] }, ], mode:'history'}) 面包屑的使用不同的路由,面包屑显示的信息会自动变化bread.vue 12345678910111213141516171819202122<template> <div> <el-card> <el-breadcrumb separator="/"> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item v-for="(item,index) in $route.matched" :key="index" >{{item.name}}</el-breadcrumb-item> </el-breadcrumb> </el-card> </div></template><script>export default {}</script><style scoped></style> home.vue 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859<template> <div class="home"> <Header></Header> <el-container class="content"> <Menu>menu</Menu> <el-container> <el-main> <Breadcrumb/> <div class="cont"> <router-view></router-view> </div> </el-main> <el-footer> <Footer></Footer> </el-footer> </el-container> </el-container> </div></template><script>import Header from "@/components/common/Header.vue";import Footer from "@/components/common/Footer.vue";import Menu from "@/components/common/Menu.vue";import Breadcrumb from '@/components/common/Breadcrumb.vue'export default { components: { Header, Footer, Breadcrumb, Menu, }, data() { return {} }}</script><!-- Add "scoped" attribute to limit CSS to this component only --><style scoped lang="less">.home { width: 100%; height: 100%; .content{ position: absolute; width: 100%; top: 60px; bottom: 0; .cont{ margin: 20px 0; } }}</style> Card 卡片12345<!-- body-style的使用 --><el-card :body-style="{padding:'0px'}"> <div style="padding-top: 4px;display: flex"> </div</div></el-card> 级联选择器新版本props的使用级联选择器太高可以在全局样式里给.el-cascader-panel设置高度为200px:props=”{ expandTrigger: ‘hover’, value: ‘cat_id’, label: ‘cat_name’, children: ‘children’ }” 多选框 1234567891011121314151617<div> <el-checkbox-group v-model="checkboxGroup1"> <el-checkbox-button v-for="city in cities" :label="city" :key="city">{{city}}</el-checkbox-button> </el-checkbox-group></div>const cityOptions = ['上海', '北京', '广州', '深圳']; export default { data () { return { checkboxGroup1: ['上海'], checkboxGroup2: ['上海'], checkboxGroup3: ['上海'], checkboxGroup4: ['上海'], cities: cityOptions }; } Avatar 头像12<el-avatar shape="square" size="small" src="https://baidu.com/logo"></el-avatar> Table 表格el-table怎样隐藏某一列el-table-column上添加v-if="false" 1234567891011121314151617181920212223<el-table v-loading="loading" :data="bczglList" @selection-change="handleSelectionChange"> <el-table-column label="id" align="center" prop="id" v-if="false" /> <el-table-column label="班次组编号" align="center" prop="bczbh" /> <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <template slot-scope="scope"> <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['kqgl:bczgl:edit']" >修改</el-button> <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['kqgl:bczgl:remove']" >删除</el-button> </template> </el-table-column></el-table> 先记着Vue同一个dom元素绑定多个点击事件如何绑定 1<el-button @click="dialogVisible = false;clearTempData()">取 消</el-button> 模板获取值 123<template slot-scope="scope"> <el-tag type="warning" v-for="ids in scope.row.typeID.split(',')">{{getGameType(ids)}}</el-tag></template> Store 数据 1agentId: _this.$store.getters.name.agentId,

2024-02-26
Vue后台系统
项目由 Vue3 + Pina + JavaScript + Ant Design Vue 创建项目12345# 直接创建npm create vite@latest my-vue-app -- --template vue# 如果要创建ts或者自定义配置的项目就用这个npm create vite 引入Ant Design Vue1npm i --save [email protected] mian.js 删掉自带的style.css文件 12345678import {createApp} from 'vue'import Antd from 'ant-design-vue';import 'ant-design-vue/dist/reset.css';import App from './App.vue'const app = createApp(App);app.use(Antd)app.mount('#app'); 安装router1npm install vue-router@4 创建src/router/index.js文件 12345678910111213141516171819202122232425262728293031323334353637383940414243444546import { createWebHistory, createRouter } from 'vue-router'/** * Note: 路由配置项 * * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 * // 若你想不管路由下面的 children 声明的个数都显示你的根路由 * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 * name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 * roles: ['admin', 'common'] // 访问路由的角色权限 * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 * meta : { noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false) title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示 activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。 } */// 公共路由export const constantRoutes = [ { path: '/login', component: () => import('@/views/login'), hidden: true },]const router = createRouter({ history: createWebHistory(), routes: constantRoutes, scrollBehavior(to, from, savedPosition) { if (savedPosition) { return savedPosition } else { return { top: 0 } } },});export default router; 配置开发环境编辑vite.config.js 123456789101112131415161718192021import { defineConfig, loadEnv } from 'vite'import path from 'path'import vue from '@vitejs/plugin-vue'// https://vitejs.dev/config/export default defineConfig(({ mode, command }) => { return { plugins: [vue()], resolve: { // https://cn.vitejs.dev/config/#resolve-alias alias: { // 设置路径 '~': path.resolve(__dirname, './'), // 设置别名 '@': path.resolve(__dirname, './src') }, // https://cn.vitejs.dev/config/#resolve-extensions extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] } }}) 项目根目录创建环境配置文件 .env.development .env.prod 12345678# 页面标题VITE_APP_TITLE = 若依管理系统# 开发环境配置VITE_APP_ENV = 'development'# 若依管理系统/开发环境VITE_APP_BASE_API = '/dev-api' 安装sass12345npm install -D sass# 直接使用就可以<style lang="scss" scoped></style> 全局样式创建src/style/index.scss文件 123456789101112131415161718@import './demo.scss';html { height: 100vh; box-sizing: border-box;}body { height: 100vh; margin: 0; //-moz-osx-font-smoothing: grayscale; //-webkit-font-smoothing: antialiased; //text-rendering: optimizeLegibility; //font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;}#app { height: 100vh;} 创建src/style/demo.scss文件 1// 这个文件是用来写css的,前面导入的这个文件,所以后面只需要写就行了 导入scss,编辑main.js 1import './style/index.scss' Ant Design Vue Icon的使用123456789101112131415<template> <a-form class="login-from"> <a-form-item size> <a-input placeholder="请输入用户名" size="large"> <template #prefix> <UserOutlined/> </template> </a-input> </a-form-item> </a-form></template><script setup> import {UserOutlined, LockOutlined} from '@ant-design/icons-vue'</script> 安装Axios1npm install axios 创建 src/utils/request.js 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556import axios from 'axios'axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'// 创建axios实例const service = axios.create({ // axios中请求配置有baseURL选项,表示请求URL公共部分 baseURL: import.meta.env.VITE_APP_BASE_API, // 超时 timeout: 10000})// request拦截器service.interceptors.request.use(config => { return config}, error => { console.log(error) Promise.reject(error)})// 响应拦截器service.interceptors.response.use(res => { // 未设置状态码则默认成功状态 const code = res.data.code || 200; if (code === 401) { return Promise.reject('无效的会话,或者会话已过期,请重新登录。') } else if (code === 500) { ElMessage({ message: msg, type: 'error' }) return Promise.reject(new Error(msg)) } else if (code === 601) { ElMessage({ message: msg, type: 'warning' }) return Promise.reject(new Error(msg)) } else if (code !== 200) { ElNotification.error({ title: msg }) return Promise.reject('error') } else { return Promise.resolve(res.data) } }, error => { console.log('err' + error) let { message } = error; if (message == "Network Error") { message = "后端接口连接异常"; } else if (message.includes("timeout")) { message = "系统接口请求超时"; } else if (message.includes("Request failed with status code")) { message = "系统接口" + message.substr(message.length - 3) + "异常"; } ElMessage({ message: message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) })export default service main.js 1import router from './router'

2023-07-08
Telegram Bot
机器人设置消息分类消息分两种: 普通文本消息(比如test) 命令消息(以'/'开头的文本,比如 /test ) 默认在群里只能收到命令消息,和机器人私聊可以接收到全部的消息,如果想让机器人在群里也能接收到全部的消息,操作如下访问BotFather,输入/setprivacy,选择自己的机器人,选择DISABLED,就可以了

2022-11-19
Python
安装虚拟环境12345678910111213141516171819202122232425262728293031323334# 判断有没有虚拟环境virtualenv -V# 安装虚拟环境# 需要sudopip install virtualenvpip install virtualenvwrapper# 查看有多少虚拟环境的文件夹workon# 创建虚拟环境文件夹mkvirtualenv 文件夹名字# 从虚拟文件夹退出deactiave# 进入虚拟环境中workon 虚拟环境名称# 删除虚拟环境rmvirutalenv# 查看虚拟环境有哪些框架,要在虚拟环境中执行pip freeze# 安装软件指定版本,要在虚拟环境中执行pip install flask==10.0.0.0# 导出虚拟环境中的所有扩展,要在虚拟环境中执行pip freeze > requirements.txt# 安装,要在虚拟环境中执行pip install -r requirements.txt centos7安装python3特别是在喜欢环境中已经安装的python2.x的版本中 1234567891011121314151617181920212223242526272829# 这个可能不一定要装sudo yum -y groupinstall "Development tools"# 需要的sudo yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel# 下载安装包wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0a1.tar.xz# 解压tar -xvxf Python-3.7.0a1.tar.xz# 复制文件夹mv Python-3.7.0 /usr/local# 进入到文件夹cd /usr/local/Python-3.7.0/# 编译,一定需要后面的参数./configure --prefix=/usr/local/bin/python3make & make install# 添加软连接ln -s /usr/local/bin/python3/bin/python3 /usr/bin/python3ln -s /usr/local/bin/python3/bin/pip3 /usr/bin/pip3# 验证python3pip3 基础1.注释123456789# 注释后面需要一个空格print("单行注释")print("单行注释") # 单行注释和代码之间至少要有两个空格"""多行注释"""print("这是多行注释") 2.算数运算符乘法的使用,用*可以拼接字符串 12345In [1]: "A" * 30Out[1]: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'In [2]: 1 * 30Out[2]: 30 优先级 幂 >* > / > % > // >+ > - 3.变量3.1.变量的类型数字型 整数 int 浮点 float(计算要小心) 布尔 布尔值可以用 and、or 和 not 运算 复数(用于科学技术的) 非数字型 String(字符串) List(列表) Tuple(元组) Dictionary(字典) 3.2.type函数12345678# 整数print(type(1))# 浮点数print(type(1.5))# 字符串print(type("hello world"))# 空值print(type(None)) 3.3.不同类型的变量之间的计算1234567891011121314151617181920212223242526272829In [10]: age =13In [11]: sex =TrueIn [12]: height = 180.1In [13]: age + sexOut[13]: 14In [14]: age + heightOut[14]: 193.1In [15]: age + heightOut[15]: 193.1# 字符串的拼接In [17]: first_name ="东尼"In [18]: last_name="安"In [19]: last_name+first_nameOut[19]: '安东尼'# 字符串不能和数字相加In [20]: last_name + 10---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-20-45feb354f2d0> in <module>----> 1 last_name + 10TypeError: can only concatenate str (not "int") to str 3.4.变量的输入12345678910# 可以不需要参数In [24]: input()123# 加参数,做提示In [27]: pwd = input("输入数字")输入数字123In [28]: pwd + "456"Out[28]: '123456' 3.5.数据类型转换 方法名 含义 str() 转成字符串 float() 转成浮点 int() 转成int 123456789101112131415161718192021222324# 数字和字符串相互转In [3]: age = 23In [4]: type(age)Out[4]: intIn [5]: age_str = str(age)In [6]: type(age_str)Out[6]: strIn [7]: type(int(age_str))Out[7]: int# 浮点转数值,缺失精度In [9]: pi = "3.14"In [10]: piOut[10]: '3.14'In [13]: type(float(pi))Out[13]: floatIn [15]: int(float(pi))Out[15]: 3 3.6.变量的格式化输出 符号 描述 %c 格式化字符(输出数值对应的ASCII码) %s 格式化字符串 %d 格式化整数(%06d,不足的补0) %x 格式化十六进制数(小写) %X 格式化十六进制数(大写) %o 格式化八进制数 %f 格式化浮点数字,可以指定小数点精度(%.2f) %% 输出%号 12345678910"""'我的名字是:anthony,请多多关照我的学号是:000001,请多多关照单价是:1.00,购买了2.00斤,总价是:2.000数据的比例是:20%"""print("我的名字是:%s,请多多关照" % "anthony")print("我的学号是:%06d,请多多关照" % 1)print("单价是:%.2f,购买了%.2f斤,总价是:%.3f" % (1,2,2))print("数据的比例是:%02d%%" % 20) 3.7.变量的命名 字母,和下划线和数字组成 不能以数字开始 不能与关键字重名 其余的符号都不行 区分大小写 =左右都要添加空格 两个单词之间用_ 4.条件控制4.1.if12345678910age = 15if age >= 18: print("成年了") print("在一个缩进的,是一个代码块")elif age<=18: print("没有成年")else: print("输入错误")print("结束了") 4.2.逻辑运算符123print(True and False)print(True or False)print(not True) 4.3.随机数1234In [17]: import randomIn [18]: random.randint(12,20)Out[18]: 12 4.3.while1234i = 0while i < 5: print("....") i += 1 4.4.continue 和 break如果是嵌套循环,用这个两个关键字,也只是结束当前的循环,不会影响外层的循环 5.函数5.1.函数注释1234# 这个也是可以注释的def test(): """这个也是可以注释的""" print("打印乘法表") 5.2.函数调用index.py 12def chengfabiao(): print("打印乘法表") test.py 12import indexindex.chengfabiao() 5.3.局部方法修改全局变量12345678910num =10def mo(): # 声明num是全部变量 global num num=100 print(num)mo()print(num) 5.4.多个返回值12345678def change(x,y): return y,xx =1y=2x,y = change(1,2)print(x)print(y) 5.5.缺省函数1234567891011121314151617def measure(age,gender=1): print(age) print(gender)def measure2(age,gender=1,name="anthony"): print(age) print(gender) print(name)measure(1)measure(1,2)# 有多个缺省的时候,需要指定参数名称measure2(1,name="anthonyyang",gender=2)# 拆包measure(1,*(2,3,4),**{"name":"anthony"}) 5.6.多值参数习惯存元祖的使用用*args,存字典的时候用**args 5.7.函数的参数-默认参数1234567891011121314def my_print(name,age): print(name,age)def my_print2(name,age=13): print(name,age)# 有默认值的形参,不能放在前面,会报错# def my_print3(age=13,name):# print(name,age)my_print("anthony",12)my_print2("anthony2",123)my_print2("anthony2") 5.8.函数的参数-关键字参数12345678910111213141516def my_print(name,address): print(name,address)my_print("anthony","广东")my_print("广东","anthony")my_print(name="anthony",address="广东")my_print(address="广东",name="anthony",)# ----------------**kw是关键字参数,且 hobby 就是一个 dict (字典)-------------def my_print2(name,address,**kw): if 'age' in kw: print("age=",kw["age"])my_print2("anthony","广东",age=123)my_print2("anthony","广东",kw={"age":123}) 5.8.函数的参数-只接受关键字参数123456789def my_print(name,*,address): print(name,address)# 报错# my_print("anthony","广东")# my_print("广东","anthony")my_print("anthony",address="广东")my_print(address="广东",name="anthony") 5.8.函数的参数-不定长参数hobby是可变参数,且 hobby 其实就是一个 tuple (元祖) 12345678910def print_user_info( name , age , sex = '男' , * hobby): # 打印用户信息 print('昵称:{}'.format(name) , end = ' ') print('年龄:{}'.format(age) , end = ' ') print('性别:{}'.format(sex) ,end = ' ' ) print('爱好:{}'.format(hobby)) return;# 调用 print_user_info 函数print_user_info( '两点水' ,18 , '女', '打篮球','打羽毛球','跑步 6.容器6.1.列表虽然列表可以存储不同类型的数据,但是在开发中,存储的都是相同类型数据,因为要迭代 123456789101112131415161718192021222324mylist=["a","b","c"]print(mylist)# 通过索引,访问列表中的值print(mylist[1])# 通过方括号的形式来截取列表中的数据,访问列表中的值# 就是从第 0 个开始取,取到第 2 个,但是不包含第 2 个print(mylist[0:2])# 通过索引对列表的数据项进行修改或更新mylist[1] = "bb"print(mylist)# 使用 append() 方法来添加列表项mylist.append("d")print(mylist)# 使用 del 语句来删除列表的的元素del mylist[3]print(mylist)# 列表长度print(len(mylist)) 6.2.元祖元祖用的是括号 与列表比较,元祖元素不能修改 123456789101112131415161718192021222324252627# 创建元祖方法1tuple1=('两点水','twowter','liangdianshui',123,456)tuple2='两点水','twowter','liangdianshui',123,456# 创建元祖方法2tuple3 = ()# 创建元祖方法3tuple4 = (123,)print(tuple1)print(tuple2)print(tuple3)print(tuple4)# 访问元祖print(tuple1[1])# 修改元祖的值mylist=[1,2,3]tuple5=("ddd",mylist)print(tuple5)mylist[1]=43print(tuple5)# 删除元祖,tuple 元组中的元素值是不允许删除的,但我们可以使用 del 语句来删除整个元组del tuple1 元祖和列表相互转换 123456789101112131415# 声明元祖In [54]: num_list = (1,2,3,4)In [55]: type(num_list)Out[55]: tuple# 元祖转成列表In [56]: my_list = list(num_list)# 修改值In [57]: my_list[0]=5# 再转成元祖In [58]: print(tuple(my_list))(5, 2, 3, 4) 6.2.字典列表是有序的 字典是无序的 12345678910111213141516171819202122232425262728names={"name":"xiaoming","age":"23"}# 取值print(names["name"])# 新增和修改(key存在,就是新增,不存在就是修改)names["address"] ="feilvb"names["name"] ="anthony123"print(names)# 删除names.pop("name")print(names)# 统计键值对的数量print(len(names))# 合并键值对,如果合并的时候有相同的key,那个value就是更新值temp = {"a":"b"}names.update(temp)print(names)# 遍历字典for k in names: print("遍历",k,names[k])# 清空字典names.clear() 6.3.setset可以理解为只有key的字典 12345678# 创建setset1 = set([1,2,3])# 添加元素set1.add(200)# 删除元素set1.remove(1) 6.4.字符串123456789101112131415str ="hello hello"print("字符串长度",len(str))print("字符串出现次数",str.count("llo"))print("取索引",str.index("llo"))print("取值",str[1])# 换行符,都是空白字符print("判断空白字符",str.isspace())print("是否以指定字符串开始",str.startswith("hello"))print("是否以指定字符串结束",str.endswith("LLO"))print("查找指定字符串",str.find("llo"))print("替换字符串",str.replace("hello","HELLO"))print(str[0:9:2])# bytes转字符串print(b"abcde".decode("utf-8")) 字符串前加 b:b 前缀代表的就是bytes 字符串前加 r:r/R:非转义的原始字符串 7.公共方法 内置函数: len max 只能比较字典的key min 只能比较字典的key 2.字符串,列表,元祖都可以切片 3.查看地址值 1id(str) 面向对象类名需要大驼峰命名法 1.基本语法1.1.创建对象1234567891011class Cat: def eat(self): print("小猫爱吃鱼") def drink(self): print("小猫爱喝水")tom = Cat()tom.eat()tom.drink() 1.2.对象内置方法(魔术方法)123456789101112131415161718192021222324252627class Cat: # 构造方法 def __init__(self,name): print("初始化方法") self.name=name # 成员方法 def eat(self): print(self.name+"爱吃鱼") # 成员方法 def drink(self): print(self.name+"爱喝水") # 魔术方法 def __del__(self): print("销毁方法") # 魔术方法 def __str__(self): return "重写tostring"tom = Cat("Tom")tom.eat()tom.drink()print(tom) 1.3.私有属性和方法1234567891011121314151617181920212223242526272829303132333435class Cat: # 构造方法 def __init__(self,name): print("初始化方法") self.name=name self.__age =18 def eat(self): print(self.name+"爱吃鱼") def drink(self): print(self.name+"爱喝水") def say_age(self): print("年纪是:"+str(self.__age)) # 调用私有方法 self.__private_method() def __private_method(self): print("私有方法") def __del__(self): print("销毁方法") def __str__(self): return "重写tostring"tom = Cat("Tom")tom.eat()tom.drink()tom.say_age()print(tom)# 这种访问方式,也是可以访问到私有的属性和方法的print(tom._Cat__age) 1.4.继承和重写123456789101112131415161718192021222324252627282930class Animal: def __init__(self): self.name1 =100 self.__num2 = 200 def eat(self): print("动物吃") def run(self): print("动物跑") # 子类不允许调用私有方法 def __test(self): print("父类可以访问到私有属性和私有方法")class Dog(Animal): def run(self): print("子类打印,开始调用父类方法") super().run() print("调用完父类方法")# animal = Animal()# animal.eat()# animal.run()dog = Dog()dog.eat()dog.run() 1.5.多继承尽量避免使用多继承,如果继承了两个累,两个类有相同的方法和属性,容易混淆 123456789101112131415161718192021222324252627282930class Animal: def __init__(self): self.name1 = 100 self.__num2 = 200 def eat(self): print("动物吃") def run(self): print("动物跑") # 子类不允许调用私有方法 def __test(self): print("父类可以访问到私有属性和私有方法")class Zoo: def eat(self): print("动物园吃饭")class Dog(Animal, Zoo): def run(self): print("子类打印,开始调用父类方法") super().run() print("调用完父类方法")dog = Dog()dog.eat() 1.6.多态12345678910111213141516171819202122232425262728class Dog(object): def __init__(self,name): self.name = name def game(self): print("蹦蹦跳跳",self.name)class Xiaotianquan(Dog): def game(self): print("哮天犬",self.name)class Person(object): def __init__(self,name): self.name = name def game_with_dog(self,dog): print("人和狗玩耍",self.name,dog.name) dog.game()# dog = Dog("旺财")dog = Xiaotianquan("旺财")xiaoming = Person("xiaoming")xiaoming.game_with_dog(dog) 1.7.类属性和类方法和静态方法类属性 相当于静态变量 123456class Dog(object): # 类属性 age = 12 def __init__(self,name): self.name = name 类方法 123456789101112class Dog(object): # 类属性 age = 12 # 类方法 @classmethod def show_age(cls): print("静态方法",cls.age)dog = Dog()Dog.show_age() 静态方法,在不用方法类属性和静态属性的时候,可以定义成静态方法 1234567891011121314151617181920class Dog(object): # 类属性 age = 12 # 类方法 @classmethod def show_age(cls): print("类方法",cls.age) @staticmethod def static_method(): print("静态方法")dog = Dog()# 调用类方法Dog.show_age()# 调用静态方法Dog.static_method() 2.异常2.1.异常的完整语法1234567891011try: num = int(input("输入一个整数:")) 10 / numexcept ZeroDivisionError: print("请不要输入数字0")except Exception as result: print("未知错误 %s" % result)else: print("没有异常才会执行的代码")finally: print("无论是否有异常,都会异常的代码") 2.2.主动抛异常123456789101112def check(name): if(name == "anthony"): return "是安东尼" else: # 主动抛异常 raise Exception("不是安东尼")# 捕获异常try: print(check("anthony2"))except Exception as result: print(result) 3.模块导入的语法如下:[from 模块名】import [模块 1类1变量1函数1x[as别名]常用的组合形式如: import 模块名 from 模块名 import 类、变量、方法等 from 模块名 import * import 模块名 as 别名 from 模块名import 功能名 as 别名 3.1.导入模块不推荐使用, 12import pkg1import pkg2 3.2.简单的使用my_module.py 1234567title = "模块2"def say_hello(): print("i am module : %s " % title)class Cat: pass index.py 1234567import my_module# use module methodmy_module.say_hello()dog = my_module.Cat()print(dog) 3.3.导入的时候也可以起别名别名要使用大驼峰命名 1import my_module as MyModule 3.4.from…import导入一部分工具 使用的时候,就不需要写那个模块名了,直接使用 1234from my_module import say_hellofrom my_module import Catsay_hello()cat = Cat() 3.5.作为模块的正常写法123456def main(): pass# 有了这个之后,被别的模块调用的时候if __name__ = "__main__" main 3.6.包包 包含多个模块 创建一个新的文件夹,在文件夹里面创建__init__.py 123# . 是相对路径名from . import send_messagefrom . import receive_message 在文件夹里面创建两个模块 receive_message.py 12def receive(): print("接受信息") send_message.py 12def send(text): print("发送 %s" % text) 调用模块 1234import hm_messagehm_message.send_message.send('hello')hm_message.receive_message.receive() 3.7.发布模块1.创建setup.py 1234567from distutils.core import setupsetup(name="hm_message", version="1.0", description="push", py_modules=["hm_message.send_message", "hm_message.receive_message"]) 2.命令 12python setup.py buildpython setup.py sdist 3.8.安装模块123# 手动安装模块tar xxx.tar.gzpython setup.py install pymssql访问https://www.lfd.uci.edu/~gohlke/pythonlibs/#pymssql 下载[pymssql‑2.1.4‑cp38‑cp38‑win32.whl] 网络编程0.socket的历史套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。 一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯或IPC。 套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。 基于文件类型的套接字家族 - 套接字家族的名字:AF_UNIX unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信 基于网络类型的套接字家族 - 套接字家族的名字:AF_INET (还有AF_INET6被用于ipv6, 还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET) 套接字把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。 所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的 1.udp发送端 123456789101112131415161718192021import socketdef main(): # 创建一个udp套接字 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while True: send_data = str = input("输入要发送的数据") if send_data == "exit": break # udp_socket.sendto(b"这是消息",("192.169.0.1",8000)) udp_socket.sendto(send_data.encode("utf-8"),("127.0.0.1",7788)) # 关闭套接字 udp_socket.close()if __name__ == '__main__': main() 接受者 1234567891011121314151617181920import socketdef main(): # 创建一个udp套接字 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定本地相关信息 local_addr = ("",7788) udp_socket.bind(local_addr) while True: # 等待接收对方发送的数据 recv_data = udp_socket.recvfrom(1024) print(recv_data[0].decode("gbk")) # 关闭套接字 udp_socket.close()if __name__ == '__main__': main() 2.tcp3.socket使用socket访问redis 12345678910111213141516171819import sockethost = '10.0.2.110'port = 6379buf_size = 1conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)conn.connect((host, port))cmd = 'SELECT 2\n'.encode('utf-8')r = conn.sendall(cmd)cmd = 'PING\n'.encode('utf-8')conn.sendall(cmd)while True: res = conn.recv(buf_size) print(res) if not res: breakconn.close() 服务端套接字函数 123456789101112131415161718192021222324252627282930313233s.bind() #绑定(主机,端口号)到套接字s.listen() #开始TCP监听s.accept() #被动接受TCP客户的连接,(阻塞式)等待连接的到来**客户端套接字函数**s.connect() #主动初始化TCP服务器连接s.connect_ex() #connect()函数的扩展版本,出错时返回出错码,而不是抛出异常**公共用途的套接字函数(客户端和服务端都能使用)**s.recv() #接收TCP数据s.send() #发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)s.sendall() #发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)s.recvfrom() #接收UDP数据s.sendto() #发送UDP数据s.getpeername() #连接到当前套接字的远端的地址s.getsockname() #当前套接字的地址s.getsockopt() #返回指定套接字的参数s.setsockopt() #设置指定套接字的参数s.close() #关闭套接字 Requestpost请求参数123456789101112131415161718# 表单提交import requestsdata = { "name":"anthony", "age":"12"}requests.post(url=url,data=data)# json提交import requestsjson_data = { "name":"anthony", "age":"12"}requests.post(url=url,json=json_data) cookie操作1234cookies={ 'auther':'11223'}request.post(url=url,data=data,cookies=cookies) headers1234headers ={ 'auth':'123'}request.post(url=url,data=data,cookies=cookies,headers=headers) 请求超时12# 如果超过2s就超时报错requests.post(url=url,timeout=2) 鉴权有些页面,需要,比如spring secuity的页面 1requests.post(url=url,timeout=2,auth=('anthony','123456')) 编码12# 先编码 再解码r.text.encode('utf-8').decode(unicode_escape) 下载流21234567url = "http://wx4.sinaimg.cn/large/d030806aly1fq1vn8j0ajj21ho28bduy.jpg"rsp = requests.get(url, stream=True)with open('1.jpg', 'wb') as f: # 边下载边存硬盘, chunk_size 可以自由调整为可以更好地适合您的用例的数字 for i in rsp.iter_content(chunk_size=1024): f.write(i) requests.get(url)默认是下载在内存中的,下载完成才存到硬盘上 Response.iter_content来边下载边存硬盘 Flask路由入门12345678910from flask import Flaskapp = Flask(__name__)@app.route('/login')def hello_world(): return 'Hello World!'if __name__ == '__main__': app.run() URL上动态参数1234567891011121314from flask import Flaskapp = Flask(__name__)@app.route("/")def hello_world(): return "hello world"@app.route("/<int:age>")def play_game(age): return "hello world"+str(age)if __name__ == '__main__': app.run(debug=True) 自定义转换器1234567891011121314151617181920212223242526from flask import Flaskfrom werkzeug.routing import BaseConverterapp = Flask(__name__)# 自定义,并且继承BaseConverterclass MyConverter(BaseConverter): def __init__(self, map, regex): # map 就是app.url_map 也就是请求路径 # regex,就是d{3}, 也就是自定义的规则 super(MyConverter, self).__init__(map) self.regex = regexapp.url_map.converters["haha"] = [email protected]('/<haha("\d{3}"):age>')def play_game2(age): return "自定义转换器,接收3位" + str(age)@app.route('/<haha("\d{4}"):age>')def play_game3(age): return "自定义转换器,接收4位" + str(age)if __name__ == '__main__': app.run(debug=True) 给路由添加请求方式12345678910from flask import Flaskapp = Flask(__name__)@app.route('/',methods=['POST'])def play_game2(age): return "自定义转换器,接收3位" + str(age)if __name__ == '__main__': app.run(debug=True) 返回响应体123456789101112131415161718192021from flask import Flaskapp = Flask(__name__)@app.route('/')def method1(): """直接返回字符串信息""" return "返回字符串信息"@app.route('/2')def method2(): """直接返回字符串信息""" return "返回字符串信息",[email protected]('/3')def method3(): """直接返回字符串信息""" return {"name":"anthony"},200,{"Content-Type":"application/json","token":"123456"}if __name__ == '__main__': app.run(debug=True) 重定向12345678910from flask import Flask,redirectapp = Flask(__name__)@app.route('/')def method1(): return redirect("http://baidu.com")if __name__ == '__main__': app.run(debug=True) 跳转页面123456789101112131415161718192021222324from flask import Flask, render_template, request,redirectapp = Flask(__name__)@app.route('/login', methods=['GET', 'POST'])def hello_world(): print("请求来了") # 获取post传过来的值 user = request.form.get("user") pwd = request.form.get("pwd") if user == "anthony" and pwd == "123456": # return render_template("login.html", **{"msg": "登录成功"}) return redirect("/index") else: return render_template("login.html", **{"msg": "用户名或者密码错误"})@app.route("/index")def index(): return "欢迎登录"if __name__ == '__main__': app.run() 异常捕获123456789101112131415161718from flask import Flask,abortapp = Flask(__name__)@app.route('/')def method1(): """abort 异常抛出""" abort(404) return "hello world""""捕获异常"""@app.errorhandler(404)def method1(e): print(e) return "页面找不到"if __name__ == '__main__': app.run(debug=True) 获取请求参数Form12345678910111213141516171819from flask import Flask, render_template, requestapp = Flask(__name__)@app.route('/login', methods=['GET', 'POST'])def hello_world(): print("请求来了") # 获取post传过来的值 user = request.form.get("user") pwd = request.form.get("pwd") if user == "anthony" and pwd == "123456": return render_template("login.html", **{"msg": "登录成功"}) else: return render_template("login.html", **{"msg": "用户名或者密码错误"})if __name__ == '__main__': app.run() 获取请求参数Body123456789101112from flask import Flask, requestapp = Flask(__name__)@app.route('/callback')def hello_world(): data = request.get_data() print(data) return 'Hello, World!'if __name__ == "__main__": app.run(debug=True, port=10086) 环境变量/配置文件12345678910111213141516171819202122from flask import Flask,redirect,requestapp = Flask(__name__)# 1.从配置类中加载class MyConfig(object): DEBUG =True# app.config.from_object(MyConfig)# 2.从配置文件中加载# app.config.from_pyfile("Config.ini")# 在项目的根目录创建个Config.ini文件# 3.从环境变量# app.config.from_envvar("")@app.route('/')def method1(): passif __name__ == '__main__': app.run() 钩子,类似拦截器12345678910111213141516171819202122232425262728293031from flask import Flask,redirect,requestapp = Flask(__name__)@app.before_first_requestdef before_first_request(): """只请求一次""" print("before_first_request")@app.before_requestdef before_request(): """每次都会请求""" print("before_request")@app.after_requestdef after_request(resp): """比如做json统一的返回格式""" print("after_request") return [email protected]_requestdef teardown_request(e): """最后会请求到这里,适合做异常信息统计""" print("teardown_request")@app.route('/')def method1(): return "hello world"if __name__ == '__main__': app.run(debug=True) 视图内容和模板123456789101112131415161718192021from flask import Flask, make_response, requestapp = Flask(__name__)# 设置[email protected]("/set_cookie")def set_cookie(): response = make_response("set cookie") response.set_cookie("computer","macbook pro") response.set_cookie("age","13 pro",1000) return [email protected]("/get_cookie")def get_cookie(): name = request.cookies.get("computer") age = request.cookies.get("age") return "name:%s,age:%s"%(name,age)if __name__ == '__main__': app.run(debug=True) Session1234567891011121314151617181920from flask import Flask, make_response, request, sessionapp = Flask(__name__)app.config["SECRET_KEY"]="123456"# 设置[email protected]("/set_session/<path:name>")def set_session(name): session["name"] =name return "set session"@app.route("/get_session")def get_session(): value = session.get("name") return "value:%s"%(value)if __name__ == '__main__': app.run(debug=True) orm入门12pip install flask_sqlalchemypip install pymysql 1234567891011121314151617181920212223242526272829303132333435363738from flask import Flask,render_templatefrom flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)# 设置数据库的配置信息app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://Rong:[email protected]:3306/data36"app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False# 创建sqlAlchemy对象,关联appdb = SQLAlchemy(app)# 创建模型类class Role(db.Model): __tablename__ = "roles" id =db.Column(db.Integer,primary_key=True) name = db.Column(db.String(32))class Users(db.Model): __tablename__ = "users" id =db.Column(db.Integer,primary_key=True) name = db.Column(db.String(32)) # 建立外键 role_id =db.Column(db.Integer,db.ForeignKey(Role.id))@app.route("/")def demo(): return "response"if __name__ == '__main__': # 创建数据库的表 db.drop_all() db.create_all() app.run(debug=True) 蓝图基本使用demo01.py 12345678910from flask import Flask, Blueprintfrom demo02 import blueapp = Flask(__name__)# 讲蓝图注册到app中app.register_blueprint(blue)if __name__ == '__main__': app.run(debug=True) demo02.py 123456789101112from flask import Blueprint# 创建蓝图对象blue = Blueprint("my_blue", __name__)@blue.route("/")def demo(): return "response"@blue.route("/2")def demo2(): return "response2" 蓝图包的使用目录结构:|—demo.py|—-|user||—-|user|–__init__.py|—-|user|–views.py demo.py 123456789101112from flask import Flaskfrom user import user_blueapp = Flask(__name__)# 讲蓝图注册到app中app.register_blueprint(user_blue)if __name__ == '__main__': print(app.url_map) app.run(debug=True) init.py 123456from flask import Blueprint# 创建蓝图对象user_blue = Blueprint("user", __name__)from user import views views.py 123456789from user import user_blue@user_blue.route("/")def demo(): return "response"@user_blue.route("/2")def demo2(): return "response2" Django命令12345678# 安装djangopip install django# 生成数据库 迁移文件python manage.py makemigrations# 执行迁移生成表python manage.py migrate PyCharm和Django-admin创建的项目不一样12345678910111213# 项目创建django-admin startproject 项目名# 结构项目名|----|manage.py [项目管理,启动项目,创建app,数据管理]|----|项目名同名文件夹|----|----|__init__.py|----|----|asgi.py [项目配置]|----|----|settings.py [路由]|----|----|urls.py [接收网路请求,异步]|----|----|wsgi.py [接收网路请求,同步] 12345678910# 用PyCharm创建的目录结构项目名|----|manage.py |----|templates文件夹|----|项目名同名文件夹|----|----|__init__.py|----|----|asgi.py|----|----|settings.py|----|----|urls.py|----|----|wsgi.py PyCharm创建的根目录下有一个templates目录Django-admin 是没有的,要在app下的目录创建templates settings.py 1234567891011121314151617181920212223242526272829303132333435# PyCharm创建的TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, },]# 命令行创建的TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, },] 创建应用123|项目||----|app,后台系统[独立的表结构,模板,不相互影响]|----|app,前台系统[独立的表结构,模板,不相互影响] 123456789101112131415161718192021# 创建apppython manage.py startapp app名字djangoProject├── app01 [刚创建的app]│ ├── __init__.py│ ├── admin.py [django默认admin后台,不用动]│ ├── apps.py [app启动类,不用动]│ ├── migrations [数据库的迁移的,数据库变更记录]│ │ └── __init__.py│ ├── models.py [重要,对数据库进行操作]│ ├── tests.py [单元测试]│ └── views.py [重要,函数]├── djangoProject│ ├── __init__.py│ ├── asgi.py│ ├── settings.py│ ├── urls.py│ └── wsgi.py├── manage.py└── templates 注册APP项目名→项目名同名文件夹→settings.py 12345678910INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 添加下面一行的配置,下面这个是怎么来的呢?看下面 'app01.apps.App01Config' ] 项目名→APP文件夹→apps.py 12345from django.apps import AppConfigclass App01Config(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'app01' 编写URL和视图函数对应关系编辑urls.py 在app文件夹下的views.py 1234567from django.http import HttpResponsefrom django.shortcuts import render# Create your views here.# request 必须要的def index(request): return HttpResponse("欢迎使用") 启动12# 命令行启动python ./manage.py runserver templates模板 静态资源12345678910111213141516171819202122232425djangoProject├── app01│ ├── __init__.py│ ├── admin.py│ ├── apps.py│ ├── migrations│ │ └── __init__.py│ ├── models.py│ ├── static [手动创建的]│ │ ├── css [手动创建的] │ │ ├── img [手动创建的]│ │ │ └── 1.png│ │ └── js│ ├── tests.py│ └── views.py├── db.sqlite3├── djangoProject│ ├── __init__.py│ ├── asgi.py│ ├── settings.py│ ├── urls.py│ └── wsgi.py├── manage.py└── templates └── user_list.html 12345678910111213141516171819{% load static %}<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>用户列表</title></head><body><h1>用户列表</h1>加载静态资源写法一:<img src="/static/img/1.png">写法二:<img src="{% static 'img/1.png' %}"></body></html> 数据库主意:app需要先注册 12345python ./manage.py makemigrationspython ./manage.py migrate# Pycharm->tools->Run manager.py Task 开启,可以替代python manager.py 这个前缀 1pip3 install pymysql 12345678910111213141516171819from pymysql import connectcon = connect(host="43.240.30.52", port=3306, user="yanganli_github", password="yanganli_github", database="yanganli_github", charset="utf8")cursor = con.cursor()# 查询出条数print(cursor.execute("select * from post"))for one in cursor.fetchall(): print(one)cursor.close()con.close() 自动化测试安装和命令1234567891011121314# 安装pytestpip install pytest# 安装python-html包,生成html报告pip install pytest-html# 生成allure报告pip install allure-pytest# -s 打印printpytest -s test_auth.py# 只测试这一个文件pytest -q -s test_auth.py Pycharm识别pytest 规范测试文件已test_开头 测试类已Test开头,并且不能带有init方法 测试函数以test_开头 断言基本使用assert 生成报告123456789101112# 生成html'--html=../report/report.html'# 生成xml格式的报告'--junitxml=./report/report.xml'# 生成allure报告'--alluredir','../report/reportallure'# 生成allure报告,在report的文件夹执行pytest.main(['../test_case/','--alluredir','../report/allure_raw/'])./allure serve /myitem/autotest/report/allure_raw Locust1234567pip install locust# centos需要添加环境变量# 如果locust在哪个目录,如果python安装在这个目录:/usr/local/bin/python3ln -s /usr/local/bin/python3/bin/locust /usr/bin/locustlocust --version 快速入门新建一个redis.py 12345678910111213141516class QuickstartUser(HttpUser): wait_time = between(1, 10) @task def index_page(self): self.client.get("/hello") self.client.get("/world") @task(3) def view_item(self): for item_id in range(10): self.client.get(f"/item?id={item_id}", name="/item") time.sleep(1) def on_start(self): self.client.post("/login", json={"username": "foo", "password": "bar"}) 在文件目录,执行 123locust -f redis.py# 启动成功后,访问 http://localhost:8089 写一个Locust文件Locust文件是一个普通的python文件,唯一的要求就是至少有一个类继承的User类 User一个User类标识一个用户,Locust会给每个用户模拟一个User实例,公共的属性通常在User类里被定义 wait_time 属性用户的wwait_time方法通常作用于执行的任务简直等待多长时间 这里有三个内建的等待时间的函数 constant 一段固定的时间 between 最小和最大数之间的随机时间 constant_pacing 确保任务运行一次最多不超过x秒的适应时间 举个例子,让每个用户在每个任务执行之间等待0.5s到10s 12345678from locust import User, task, betweenclass MyUser(User): @task def my_task(self): print("executing my_task") wait_time = between(0.5, 10) 也可以直接在你的类里声明wait_time方法,举个例子,下面的User类,会睡眠1s,2s… 12345678class MyUser(User): last_wait_time = 0 def wait_time(self): self.last_wait_time += 1 return self.last_wait_time ... weight 属性如果文件中存在多个用户类,并且在命令行中没有指定用户类,则Locust将生成每个用户类的相同数量。您还可以通过将用户类作为命令行参数传递来指定从同一个locustfile中使用哪些用户类 1locust -f locust_file.py WebUser MobileUser 如果希望模拟某种类型的更多用户,可以在这些类上设置权重属性,比方说,web用户是移动用户的三倍多 1234567class WebUser(User): weight = 3 ...class MobileUser(User): weight = 1 ... host 属性host属性是host的URL前缀,通常,当locust启动的时候,在locust的web界面或者在命令上中使用--hosts选项中使用 如果一个类声明了声明的host属性,它将在没有使用--host命令行或web请求仲使用 tasks属性用户类可以使用@task装饰器,将任务声明为方法,但是也可以使用下面详细描述的tasks属性来指定任务。 environment 属性对用户正在其中运行的环境的引用,使用它影响这环境,或者是运行着在它的容器中,比如去停止运行从任务方法中 1self.environment.runner.quit() 如果运行的是独立的locust实例,它将停止全部,如果是运行在工作节点,它将停止节点 on_start 和 on_stop 方法用户 或者是任务集合可以声明``on_start方法或者on_stop方法,用户将调用它自己的on_start方法在它将要开始运行的时候,on_stop方法,将在停止运行的时候调用,比如TaskSet,on_start方法被调用在模拟的用户开始执行任务,on_stop方法在停止模拟的用户执行任务的时候调用(或者被interrupt()`方法调用,或者是用被用杀掉) Tasks当启动负载测试,一个用户实例将被创建, 下载mp4 12345678910111213141516171819202122232425262728293031323334353637383940414243import osimport timeimport requestsfrom tqdm import tqdm # 进度条模块def down_from_url(url, dst): # 设置stream=True参数读取大文件 response = requests.get(url, stream=True) # 通过header的content-length属性可以获取文件的总容量 file_size = int(response.headers['content-length']) if os.path.exists(dst): # 获取本地已经下载的部分文件的容量,方便继续下载,如果不存在就从头开始下载。 first_byte = os.path.getsize(dst) else: first_byte = 0 # 如果大于或者等于则表示已经下载完成,否则继续 if first_byte >= file_size: return file_size header = {"Range": f"bytes={first_byte}-{file_size}"} pbar = tqdm(total=file_size, initial=first_byte, unit='B', unit_scale=True, desc=dst) req = requests.get(url, headers=header, stream=True) with open(dst, 'ab') as f: # 每次读取一个1024个字节 for chunk in req.iter_content(chunk_size=1024): if chunk: f.write(chunk) pbar.update(1024) pbar.close() return file_sizeif __name__ == '__main__': url = input("请输入.mp4格式的视频链接地址,按回车键确认") # 根据时间戳生成文件名 down_from_url(url, str(time.time()) + ".mp4") SSH下载服务器文件 12345678910111213141516171819202122232425262728293031323334353637383940414243444546import paramikoclass LinuxFile: def __init__(self, ip, port, username, password): try: self.ip = ip self.port = port self.username = username self.password = password self.transport = paramiko.Transport((str(self.ip), int(self.port))) self.transport.connect(username=self.username, password=self.password) self.sftp = paramiko.SFTPClient.from_transport(self.transport) except Exception as e: raise e def up_file(self, localhost_file, server_file): """ 将本地文件上传至服务器 :param localhost_file: 本地文件路径 :param server_file: 服务器保存路径 :return: """ self.sftp.put(localhost_file, server_file) def down_file(self, localhost_file, server_file): """ 将服务器文件下载至本地 :param localhost_file: 本地文件路径 :param server_file: 服务器保存路径 :return: """ self.sftp.get(localhost_file, server_file) def close(self): """ 关闭服务器 :return: """ self.transport.close()if __name__ == '__main__': test = LinuxFile('47.242.218.75', '22', 'root', 'Qwer1234') # test.up_file('../2020-10-11_20-21-28.py', '/root/2020-10-11_20-21-28.py') test.down_file('/var/log/nginx/access.log','a.log')

2023-07-02
Rime
基本概念Rime 是一个输入法框架,并不是狭义上的“输入法”,而是将各种输入法的共性抽象出来的算法框架。通过不同的配置文件,Rime 可以支持多种输入方案(Schema),这个所谓的输入方案就是我们狭义上的“输入法”。比如朙月拼音输入法就是 Rime 自带的一种输入方案,另外还有比如四叶草输入法(https://github.com/fkxxyz/rime-cloverpinyin)等等。鼠须管、小狼毫、中州韵分别是 Rime 在不同操作系统下的实现程序。Rime 的配置、词库文件均使用文本方式,便于修改。所有文件均要求以 UTF-8 编码。在配置文件中,以 # 号开头表示注释。 配置文件所在的目录Rime 有两个重要的配置目录: 共享配置目录 【中州韻】 /usr/share/rime-data/ 【小狼毫】 "安裝目錄\data" 【鼠鬚管】 "/Library/Input Methods/Squirrel.app/Contents/SharedSupport/" 用户配置目录 【中州韻】 ~/.config/ibus/rime/ (0.9.1 以下版本爲 ~/.ibus/rime/) 【小狼毫】 %APPDATA%\Rime 【鼠鬚管】 ~/Library/Rime/ 共享目录下放置的是 Rime 的预设配置,在软件版本更新时候,也会自动更新该目录下的文件。所以请不要修改该目录下的文件。 用户目录则放置用户自定义的配置文件。我们要做的修改都放在用户目录下。 对于鼠须管而言,用户目录初始时只有如下几个文件。 installion.yaml 文件记录的是当前 Rime 程序的版本信息。其中有一个字段 installation_id 用来在同步用户词典时唯一标记当前 Rime 程序。 user.yaml 文件记录用户的使用状态。比如上次“重新部署”的时间戳,上次选择的输入方案等。 build 目录下放的是每次“重新部署”后生成的文件。包括字典文件编译后生成的「.bin」文件,包括与自定义配置合并后生成的各种 yaml 配置文件。 xxx.userdb 目录下放的是对应输入方案的用户词典。即用户在使用时候选择的词组、词频等动态信息,这个目录是实时更新的。 sync 目录是用来做用户数据同步的。每个 sync/installation_id 目录对应不同电脑上的 Rime 程序的用户数据。(如果你由多台电脑安装了 Rime,并设置了同步。)按照作者的说法,Rime 的用户词典同步原理是: 手工从其他电脑复制或者从网盘自动同步 ⇒ sync/*/*.userdb.txt ⇒ 合并到本地 *.userdb ⇒ 导出到 sync/<installation_id>/*.userdb.txt。 关于调试Rime 的日志目录放在如下为止: 【中州韻】 /tmp/rime.ibus.* 【小狼毫】 %TEMP%\rime.weasel.* 【鼠鬚管】 $TMPDIR/rime.squirrel.* 早期版本 用户配置目录/rime.log 修改配置如果想要修改配置,请不要直接修改原有的 xxx.yaml 文件,而是应该新建一份 xxx.custom.yaml 文件,其中 xxx 与原文件名相同。 在 .custom.yaml 文件中对于要修改的配置项,都需要放在 patch 根节点下面。 每次修改配置,都需要在鼠须管的菜单中选择“重新部署”后才能生效。 修改候选词个数Rime 默认每次出现的候选词个数为 5 个,我们可以将其修改为 1~9 之间的任意数。 在用户目录下新建一个 default.custom.yaml 文件(default.yaml 文件可以在共享配置目录下找到),写入如下内容: 123456789patch: "menu/page_size": 9 # 字段名加不加双引号都可以 # 或者是這樣patch: menu: page_size: 8# 但是注意这种写法是覆盖整个 menu 字段。好在默认情况下,menu 下一级也只有 page_size 字段,如果是有多个下级字段,请不要这么写。 上面的 default 文件是修改所有输入方案的候选词个数,如果只想针对某个输入方案做调整,比如对于朙月输入方案,那么只需要在用户目录下建立 luna_pinyin.custom.yaml 文件并写入如上内容,再重新部署即可。(注意,对输入方案定义文件 xxx.schema.yaml 的修改,新建的文件名只需要是 xxx.custom.yaml,并不需要加上 schema,写成 xxx.schema.custom.yaml 这样。) 使用,使用快捷键F4,然后像拼音打字选候选字一样,选择就好 输入方案的可切换状态,请参考后续的 switches 章节 主题鼠须管的外观配置文件是 squirrel.yaml(小狼毫的外观配置文件是 weasel.yaml)。所以我们需要在用户配置目录下新建一个 squirrel.custom.yaml,参考或者拷贝开源项目的写法,通常有很多个主题,我们可以通过 style/color_scheme 来选择一个主题 开源项目的主题文件 参考: 鼠须管输入法配置 - 哈呜.王 (hawu.me) Rime Squirrel 鼠须管输入法配置详解 - 知乎 (zhihu.com)
评论