Jadual Kandungan
Objektif pembelajaran
Apa yang kita bina?
Sediakan Fauna
Menjana kunci pentadbir
Menulis corak GraphQL
Buat projek Flutter baru
Menyediakan pelanggan Graphql dalam Aplikasi Flutter
Halaman permohonan
Laksanakan pertanyaan dan mutasi
Tambah data baru
Padam data
Edit data
Rumah hujung hadapan web tutorial css Cara membina aplikasi mudah alih penuh dengan Flutter, Fauna, dan Graphql

Cara membina aplikasi mudah alih penuh dengan Flutter, Fauna, dan Graphql

Mar 21, 2025 am 10:34 AM

Cara membina aplikasi mudah alih penuh dengan Flutter, Fauna, dan Graphql

Flutter adalah rangka kerja UI Google untuk mewujudkan aplikasi mudah alih yang fleksibel dan ekspresif. Ia adalah salah satu rangka kerja yang paling pesat untuk pembangunan aplikasi mudah alih. Fauna, sebaliknya, adalah pangkalan data pelayan tanpa urus niaga, pemaju yang menyokong GraphQL asli. Flutter Fauna adalah perlawanan sempurna yang dibuat oleh syurga. Sekiranya anda ingin membina dan melepaskan aplikasi lengkap yang kaya dengan ciri-ciri dalam masa rekod, Flutter dan Fauna adalah alat yang betul. Dalam artikel ini, kami akan membimbing anda melalui pembinaan aplikasi flutter pertama anda menggunakan backends Fauna dan GraphQL.

Anda boleh mencari kod penuh untuk artikel ini di GitHub.

Objektif pembelajaran

Selepas membaca artikel ini, anda harus tahu bagaimana untuk:

  1. Sediakan contoh fauna,
  2. Tulis corak graphql untuk fauna,
  3. Sediakan klien GraphQL dalam aplikasi Flutter, dan
  4. Lakukan pertanyaan dan mutasi pada backend GraphQL Fauna.

Fauna vs AWS Amplify vs. Firebase : Apakah masalah yang diselesaikan oleh Fauna? Bagaimana ia berbeza dengan penyelesaian tanpa pelayan lain? Jika anda tidak biasa dengan Fauna dan ingin mengetahui lebih lanjut mengenai perbandingan Fauna dengan penyelesaian lain, saya cadangkan anda membaca artikel ini.

Apa yang kita bina?

Kami akan membina aplikasi mudah alih mudah yang membolehkan pengguna menambah, memadam dan mengemas kini filem kegemaran mereka dan siri TV.

Sediakan Fauna

Pergi ke fauna.com dan buat akaun baru. Selepas log masuk, anda sepatutnya dapat membuat pangkalan data baru.

Namakan pangkalan data anda. Saya menamakan saya flutter_demo. Seterusnya, kita boleh memilih kumpulan rantau. Untuk demo ini, kami akan memilih Klasik. Fauna adalah pangkalan data tanpa pelayan di seluruh dunia. Ia adalah satu-satunya pangkalan data yang menyokong akses membaca dan menulis latensi rendah dari mana-mana sahaja. Fikirkannya sebagai CDN (rangkaian pengedaran kandungan), tetapi ia adalah untuk pangkalan data anda. Untuk mengetahui lebih lanjut mengenai kumpulan rantau ini, ikuti panduan ini.

Menjana kunci pentadbir

Sebaik sahaja pangkalan data dibuat, pergi ke tab Keselamatan. Klik butang kunci baru dan buat kekunci baru untuk pangkalan data anda. Sila simpan kunci ini dengan betul kerana kami memerlukannya untuk operasi GraphQL.

Kami akan membuat kunci pentadbir untuk pangkalan data kami. Kunci dengan peranan pentadbir digunakan untuk menguruskan pangkalan data yang berkaitan, termasuk penyedia akses pangkalan data, subdatabase, dokumen, fungsi, indeks, kunci, token, dan peranan yang ditentukan oleh pengguna. Anda boleh mengetahui lebih lanjut mengenai pelbagai kunci keselamatan Fauna dan peranan akses dalam pautan di bawah.

Kami akan membina aplikasi mudah yang membolehkan pengguna menambah, mengemas kini dan memadam watak TV kegemaran mereka.

Buat projek Flutter baru

Mari buat projek Flutter baru dengan menjalankan arahan berikut.

 <code>flutter create my_app</code>
Salin selepas log masuk

Dalam direktori projek, kami akan membuat fail baru bernama Graphql/schema.graphql.

Dalam fail skema, kami akan menentukan struktur koleksi. Koleksi di fauna adalah serupa dengan jadual dalam SQL. Kami hanya memerlukan satu set sekarang. Kami namakan wataknya.

 <code>### schema.graphql type Character { name: String! description: String! picture: String } type Query { listAllCharacters: [Character] }</code>
Salin selepas log masuk

Seperti yang ditunjukkan di atas, kami menentukan jenis yang dipanggil watak yang mempunyai pelbagai sifat (iaitu, nama, keterangan, gambar, dll.). Hartanah boleh dianggap sebagai lajur pangkalan data SQL atau pasangan nilai utama pangkalan data NoSQL. Kami juga menentukan pertanyaan. Pertanyaan ini mengembalikan senarai peranan.

Sekarang mari kita kembali ke papan pemuka Fauna. Klik GraphQL dan klik Mod Import untuk memuat naik mod kami ke Fauna.

Selepas import selesai, kami akan melihat Fauna menghasilkan pertanyaan dan mutasi GraphQL.

Tidak suka generasi graphql automatik? Ingin mempunyai kawalan yang lebih baik terhadap logik perniagaan anda? Dalam kes ini, Fauna membolehkan anda menentukan parser GraphQL tersuai. Untuk mengetahui lebih lanjut, klik pautan ini.

Menyediakan pelanggan Graphql dalam Aplikasi Flutter

Mari buka fail pubspec.yaml dan tambahkan kebergantungan yang diperlukan.

 <code>... dependencies: graphql_flutter: ^4.0.0-beta hive: ^1.3.0 flutter: sdk: flutter ...</code>
Salin selepas log masuk

Kami telah menambah dua kebergantungan di sini. Graphql_flutter adalah Perpustakaan Pelanggan Graphql Flutter. Ia mengintegrasikan semua ciri moden klien GraphQL ke dalam satu pakej yang mudah digunakan. Kami juga menambah pakej sarang sebagai kebergantungan kami. HIVE adalah pangkalan data nilai utama yang ditulis dalam Pure Dart untuk penyimpanan tempatan. Kami menggunakan sarang untuk cache pertanyaan graphql kami.

Seterusnya, kami akan membuat fail baru lib/client_provider.dart. Kami akan membuat kelas penyedia dalam fail yang akan mengandungi konfigurasi Fauna kami.

Untuk menyambung ke API GraphQL Fauna, kita perlu membuat GraphQLClient terlebih dahulu. GraphqlClient memerlukan cache dan pautan untuk dimulakan. Mari lihat kod di bawah.

 <code>// lib/client_provider.dart import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:flutter/material.dart'; ValueNotifier<graphqlclient> clientFor({ @required String uri, String subscriptionUri, }) { final HttpLink httpLink = HttpLink( uri, ); final AuthLink authLink = AuthLink( getToken: () async => 'Bearer fnAEPAjy8QACRJssawcwuywad2DbB6ssrsgZ2-2', ); Link link = authLink.concat(httpLink); return ValueNotifier<graphqlclient> ( GraphQLClient( cache: GraphQLCache(store: HiveStore()), link: link, ), ); }</graphqlclient></graphqlclient></code>
Salin selepas log masuk

Dalam kod di atas, kami mencipta Valuenotifier untuk membungkus GraphqlClient. Perhatikan bahawa kami mengkonfigurasi authLink pada baris 13-15 (diserlahkan). Pada baris 14, kami menambah kunci pentadbir dari Fauna sebagai sebahagian daripada token. Di sini, saya mengikat kunci admin. Walau bagaimanapun, dalam aplikasi pengeluaran, kita mesti mengelakkan kekunci keselamatan fauna.

Terdapat beberapa cara untuk menyimpan kekunci dalam aplikasi berkilauan. Sila periksa blog ini untuk rujukan.

Kami mahu dapat memanggil pertanyaan dan mutasi dari mana -mana widget dalam aplikasi. Untuk melakukan ini, kita perlu membungkus widget kita menggunakan widget GraphQLProvider.

 <code>// lib/client_provider.dart .... /// 使用`graphql_flutter`客户端包装根应用程序。 /// 我们使用缓存进行所有状态管理。 class ClientProvider extends StatelessWidget { ClientProvider({ @required this.child, @required String uri, }) : client = clientFor( uri: uri, ); final Widget child; final ValueNotifier<graphqlclient> client; @override Widget build(BuildContext context) { return GraphQLProvider( client: client, child: child, ); } }</graphqlclient></code>
Salin selepas log masuk

Seterusnya, kami pergi ke fail main.dart dan bungkus widget utama kami dengan widget ClientProvider. Mari lihat kod di bawah.

 <code>// lib/main.dart ... void main() async { await initHiveForFlutter(); runApp(MyApp()); } final graphqlEndpoint = 'https://graphql.fauna.com/graphql'; class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ClientProvider( uri: graphqlEndpoint, child: MaterialApp( title: 'My Character App', debugShowCheckedModeBanner: false, initialRoute: '/', routes: { '/': (_) => AllCharacters(), '/new': (_) => NewCharacter(), } ), ); } }</code>
Salin selepas log masuk

Pada ketika ini, semua widget hiliran kami akan dapat menjalankan pertanyaan dan fungsi mutasi dan boleh berinteraksi dengan API GraphQL.

Halaman permohonan

Permohonan demo mestilah mudah dan mudah difahami. Mari kita teruskan dan buat widget senarai mudah yang akan memaparkan senarai semua peranan. Mari buat fail lib/skrin/list characters.dart baru. Dalam fail ini, kami akan menulis widget baru yang dipanggil AllCharacters.

 <code>// lib/screens/character-list.dart.dart class AllCharacters extends StatelessWidget { const AllCharacters({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ SliverAppBar( pinned: true, snap: false, floating: true, expandedHeight: 160.0, title: Text( 'Characters', style: TextStyle( fontWeight: FontWeight.w400, fontSize: 36, ), ), actions:<widget> [ IconButton( padding: EdgeInsets.all(5), icon: const Icon(Icons.add_circle), tooltip: 'Add new entry', onPressed: () { Navigator.pushNamed(context, '/new'); }, ), ], ), SliverList( delegate: SliverChildListDelegate([ Column( children: [ for (var i = 0; i _CharacterTileeState(); } class _CharacterTileState extends State<charactertile> { @override Widget build(BuildContext context) { return Container( child: Text("Character Tile"), ); } }</charactertile></widget></code>
Salin selepas log masuk

Seperti yang ditunjukkan dalam kod di atas, [baris 37] kami mempunyai gelung yang mengisi senarai dengan beberapa data palsu. Akhirnya, kami akan melakukan pertanyaan GraphQL pada backend Fauna dan dapatkan semua peranan dari pangkalan data. Sebelum kita melakukan ini, mari kita cuba menjalankan permohonan kita. Kami boleh menjalankan aplikasi kami menggunakan arahan berikut

 <code>flutter run</code>
Salin selepas log masuk

Pada ketika ini, kita harus dapat melihat skrin berikut.

Laksanakan pertanyaan dan mutasi

Sekarang kita mempunyai beberapa widget asas yang kita boleh terus menyambung ke pertanyaan GraphQL. Kami mahu mendapatkan semua peranan dari pangkalan data dan bukannya rentetan keras dan melihatnya dalam widget AllCharacters.

Mari kembali ke taman permainan GraphQL Fauna. Perhatikan bahawa kami boleh menjalankan pertanyaan berikut untuk menyenaraikan semua peranan.

 <code>query ListAllCharacters { listAllCharacters(_size: 100) { data { _id name description picture } after } }</code>
Salin selepas log masuk

Untuk melakukan pertanyaan ini dari widget kami, kami perlu membuat beberapa perubahan kepadanya.

 <code>import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:todo_app/screens/Character-tile.dart'; String readCharacters = ";";"; query ListAllCharacters { listAllCharacters(_size: 100) { data { _id name description picture } after } } ";";";; class AllCharacters extends StatelessWidget { const AllCharacters({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ SliverAppBar( pinned: true, snap: false, floating: true, expandedHeight: 160.0, title: Text( 'Characters', style: TextStyle( fontWeight: FontWeight.w400, fontSize: 36, ), ), actions:<widget> [ IconButton( padding: EdgeInsets.all(5), icon: const Icon(Icons.add_circle), tooltip: 'Add new entry', onPressed: () { Navigator.pushNamed(context, '/new'); }, ), ], ), SliverList( delegate: SliverChildListDelegate([ Query(options: QueryOptions( document: gql(readCharacters), // 我们要执行的graphql查询pollInterval: Duration(seconds: 120), // 重新获取间隔), builder: (QueryResult result, { VoidCallback refetch, FetchMore fetchMore }) { if (result.isLoading) { return Text('Loading'); } return Column( children: [ for (var item in result.data\['listAllCharacters'\]['data']) CharacterTile(Character: item, refetch: refetch), ], ); }) ]) ) ], ), ); } }</widget></code>
Salin selepas log masuk

Pertama, kami menentukan rentetan pertanyaan untuk mendapatkan semua peranan dari pangkalan data [baris 5 hingga 17]. Kami membungkus widget senarai menggunakan widget pertanyaan di flutter_graphql.

Jangan ragu untuk melihat dokumentasi rasmi Perpustakaan Flutter_Graphql.

Dalam parameter pilihan pertanyaan, kami menyediakan rentetan pertanyaan GraphQL itu sendiri. Kita boleh lulus sebarang nombor titik terapung untuk parameter pollinterval. Selang Poll Menentukan berapa lama kita mahu memulihkan data dari backend. Widget juga mempunyai fungsi pembina standard. Kami boleh menggunakan fungsi pembina untuk lulus hasil pertanyaan, dapatkan semula fungsi panggil balik, dan dapatkan lebih banyak fungsi panggil balik ke dalam pokok widget.

Seterusnya, saya akan mengemas kini widget Watak untuk memaparkan data aksara pada skrin.

 <code>// lib/screens/character-tile.dart ... class CharacterTile extends StatelessWidget { final Character; final VoidCallback refetch; final VoidCallback updateParent; const CharacterTile({ Key key, @required this.Character, @required this.refetch, this.updateParent, }) : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: () { }, child: Padding( padding: const EdgeInsets.all(10), child: Row( children: [ Container( height: 90, width: 90, decoration: BoxDecoration( color: Colors.amber, borderRadius: BorderRadius.circular(15), image: DecorationImage( fit: BoxFit.cover, image: NetworkImage(Character['picture']) ) ), ), SizedBox(width: 10), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( Character['name'], style: TextStyle( color: Colors.black87, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), Text( Character['description'], style: TextStyle( color: Colors.black87, ), maxLines: 2, ), ], ) ) ], ), ), ); } }</code>
Salin selepas log masuk

Tambah data baru

Kami boleh menambah peranan baru ke pangkalan data kami dengan menjalankan mutasi berikut.

 <code>mutation CreateNewCharacter($data: CharacterInput!) { createCharacter(data: $data) { _id name description picture } }</code>
Salin selepas log masuk

Untuk menjalankan mutasi ini dari widget kami, kami perlu menggunakan widget mutasi dari perpustakaan Flutter_Graphql. Mari buat widget baru dengan bentuk mudah untuk pengguna berinteraksi dan memasukkan data. Selepas menyerahkan borang, mutasi createcharacter akan dipanggil.

 <code>// lib/screens/new.dart ... String addCharacter = ";";"; mutation CreateNewCharacter(\$data: CharacterInput!) { createCharacter(data: \$data) { _id name description picture } } ";";";; class NewCharacter extends StatelessWidget { const NewCharacter({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Add New Character'), ), body: AddCharacterForm() ); } } class AddCharacterForm extends StatefulWidget { AddCharacterForm({Key key}) : super(key: key); @override _AddCharacterFormState createState() => _AddCharacterFormState(); } class _AddCharacterFormState extends State<addcharacterform> { String name; String description; String imgUrl; @override Widget build(BuildContext context) { return Form( child: Padding( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextField( decoration: const InputDecoration( icon: Icon(Icons.person), labelText: 'Name *', ), onChanged: (text) { name = text; }, ), TextField( decoration: const InputDecoration( icon: Icon(Icons.post_add), labelText: 'Description', ), minLines: 4, maxLines: 4, onChanged: (text) { description = text; }, ), TextField( decoration: const InputDecoration( icon: Icon(Icons.image), labelText: 'Image Url', ), onChanged: (text) { imgUrl = text; }, ), SizedBox(height: 20), Mutation( options: MutationOptions( document: gql(addCharacter), onCompleted: (dynamic resultData) { print(resultData); name = ''; description = ''; imgUrl = ''; Navigator.of(context).push( MaterialPageRoute(builder: (context) => AllCharacters()) ); }, ), builder: ( RunMutation runMutation, QueryResult result, ) { return Center( child: ElevatedButton( child: const Text('Submit'), onPressed: () { runMutation({ 'data': { ";picture";: imgUrl, ";name";: name, ";description";: description, } }); }, ), ); } ) ], ), ), ); } }</addcharacterform></code>
Salin selepas log masuk

Seperti yang dapat dilihat dari kod di atas, widget mutasi berfungsi dengan sangat sama dengan widget pertanyaan. Di samping itu, widget mutasi memberikan kita fungsi oncomplete. Fungsi ini mengembalikan hasil kemas kini dalam pangkalan data selepas mutasi selesai.

Padam data

Kita boleh memadam peranan dari pangkalan data dengan menjalankan mutasi DeleteCharacter. Kita boleh menambah mutan ini ke watak kita dan mencetuskannya apabila butang ditekan.

 <code>// lib/screens/character-tile.dart ... String deleteCharacter = ";";"; mutation DeleteCharacter(\$id: ID!) { deleteCharacter(id: \$id) { _id name } } ";";";; class CharacterTile extends StatelessWidget { final Character; final VoidCallback refetch; final VoidCallback updateParent; const CharacterTile({ Key key, @required this.Character, @required this.refetch, this.updateParent, }) : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: () { showModalBottomSheet( context: context, builder: (BuildContext context) { print(Character['picture']); return Mutation( options: MutationOptions( document: gql(deleteCharacter), onCompleted: (dynamic resultData) { print(resultData); this.refetch(); }, ), builder: ( RunMutation runMutation, QueryResult result, ) { return Container( height: 400, padding: EdgeInsets.all(30), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children:<widget> [ Text(Character['description']), ElevatedButton( child: Text('Delete Character'), onPressed: () { runMutation({ 'id': Character['_id'], }); Navigator.pop(context); }, ), ], ), ), ); } ); } ); }, child: Padding( padding: const EdgeInsets.all(10), child: Row( children: [ Container( height: 90, width: 90, decoration: BoxDecoration( color: Colors.amber, borderRadius: BorderRadius.circular(15), image: DecorationImage( fit: BoxFit.cover, image: NetworkImage(Character['picture']) ) ), ), SizedBox(width: 10), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( Character['name'], style: TextStyle( color: Colors.black87, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), Text( Character['description'], style: TextStyle( color: Colors.black87, ), maxLines: 2, ), ], ) ) ], ), ), ); } }</widget></code>
Salin selepas log masuk

Edit data

Data pengeditan adalah sama seperti menambah dan memadam. Ia hanya mutasi lain dalam API GraphQL. Kami boleh membuat widget bentuk role edit yang serupa dengan widget bentuk peranan baru. Satu -satunya perbezaan ialah penyuntingan borang akan menjalankan mutasi updatecharacter. Untuk mengedit, saya mencipta widget baru lib/skrin/edit.dart. Berikut adalah kod untuk widget ini.

 <code>// lib/screens/edit.dart String editCharacter = """ mutation EditCharacter(\$name: String!, \$id: ID!, \$description: String!, \$picture: String!) { updateCharacter(data: { name: \$name description: \$description picture: \$picture }, id: \$id) { _id name description picture } } """; class EditCharacter extends StatelessWidget { final Character; const EditCharacter({Key key, this.Character}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Edit Character'), ), body: EditFormBody(Character: this.Character), ); } } class EditFormBody extends StatefulWidget { final Character; EditFormBody({Key key, this.Character}) : super(key: key); @override _EditFormBodyState createState() => _EditFormBodyState(); } class _EditFormBodyState extends State<editformbody> { String name; String description; String picture; @override Widget build(BuildContext context) { return Container( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextFormField( initialValue: widget.Character['name'], decoration: const InputDecoration( icon: Icon(Icons.person), labelText: 'Name *', ), onChanged: (text) { name = text; } ), TextFormField( initialValue: widget.Character['description'], decoration: const InputDecoration( icon: Icon(Icons.person), labelText: 'Description', ), minLines: 4, maxLines: 4, onChanged: (text) { description = text; } ), TextFormField( initialValue: widget.Character['picture'], decoration: const InputDecoration( icon: Icon(Icons.image), labelText: 'Image Url', ), onChanged: (text) { picture = text; }, ), SizedBox(height: 20), Mutation( options: MutationOptions( document: gql(editCharacter), onCompleted: (dynamic resultData) { print(resultData); Navigator.of(context).push( MaterialPageRoute(builder: (context) => AllCharacters()) ); }, ), builder: ( RunMutation runMutation, QueryResult result, ) { print(result); return Center( child: ElevatedButton( child: const Text('Submit'), onPressed: () { runMutation({ 'id': widget.Character['_id'], 'name': name != null ? name : widget.Character['name'], 'description': description != null ? description : widget.Character['description'], 'picture': picture != null ? picture : widget.Character['picture'], }); }, ), ); } ), ] ) ), ); } }</editformbody></code>
Salin selepas log masuk

Anda boleh melihat kod penuh artikel ini seperti berikut.

Ada soalan mengenai fauna atau berkibar? Anda boleh menghubungi saya di Twitter @Haqueshadid

Github ### Langkah seterusnya

Tujuan utama artikel ini adalah untuk membuat anda bermula dengan Flutter dan Fauna. Kami hanya menyentuh permukaan di sini. Ekosistem Fauna menyediakan aplikasi mudah alih anda dengan backend yang lengkap, automatik, pemaju yang lengkap sebagai perkhidmatan. Sekiranya matlamat anda adalah untuk melepaskan aplikasi mudah alih rentas platform yang boleh digunakan untuk pengeluaran dalam masa rekod, cuba Fauna dan Flutter .

Saya sangat mengesyorkan anda menyemak laman web dokumentasi rasmi Fauna. Jika anda berminat untuk mempelajari lebih lanjut mengenai klien GraphQL Dart/Flutter, lihat repositori GitHub rasmi Graphql_flutter.

Saya mengucapkan selamat datang kepada anda, sampai jumpa lagi.

Atas ialah kandungan terperinci Cara membina aplikasi mudah alih penuh dengan Flutter, Fauna, dan Graphql. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

<🎜>: Bubble Gum Simulator Infinity - Cara Mendapatkan dan Menggunakan Kekunci Diraja
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Sistem Fusion, dijelaskan
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers of the Witch Tree - Cara Membuka Kunci Cangkuk Bergelut
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Tutorial Java
1670
14
Tutorial PHP
1274
29
Tutorial C#
1256
24
Perbandingan pembekal bentuk statik Perbandingan pembekal bentuk statik Apr 16, 2025 am 11:20 AM

Mari kita cuba menyusun istilah di sini: "Penyedia Borang Statik." Anda membawa html anda

Bukti konsep untuk menjadikan sass lebih cepat Bukti konsep untuk menjadikan sass lebih cepat Apr 16, 2025 am 10:38 AM

Pada permulaan projek baru, kompilasi SASS berlaku dalam sekejap mata. Ini terasa hebat, terutamanya apabila ia dipasangkan dengan BrowserSync, yang dimuat semula

Berita Platform Mingguan: Atribut Memuat HTML, Spesifikasi ARIA Utama, dan Bergerak Dari IFRAME ke Shadow Dom Berita Platform Mingguan: Atribut Memuat HTML, Spesifikasi ARIA Utama, dan Bergerak Dari IFRAME ke Shadow Dom Apr 17, 2025 am 10:55 AM

Pada minggu ini, berita platform, Chrome memperkenalkan atribut baru untuk memuatkan, spesifikasi aksesibiliti untuk pemaju web, dan gerakan BBC

Beberapa tangan dengan elemen dialog HTML Beberapa tangan dengan elemen dialog HTML Apr 16, 2025 am 11:33 AM

Ini saya melihat elemen HTML untuk kali pertama. Saya telah menyedarinya untuk seketika, tetapi Haven &#039; t mengambilnya untuk putaran lagi. Ia mempunyai cukup keren dan

Kertas kerja Kertas kerja Apr 16, 2025 am 11:24 AM

Beli atau Membina adalah perdebatan klasik dalam teknologi. Membina barang sendiri mungkin berasa lebih murah kerana tidak ada item baris pada bil kad kredit anda, tetapi

Di manakah 'Langgan Podcast' pautan ke? Di manakah 'Langgan Podcast' pautan ke? Apr 16, 2025 pm 12:04 PM

Untuk sementara waktu, iTunes adalah anjing besar dalam podcasting, jadi jika anda mengaitkan "Langgan Podcast" untuk suka:

Berita Platform Mingguan: Bookmarket Jarak Teks, Menunggu Tahap Teratas, Penunjuk Memuatkan AMP Baru Berita Platform Mingguan: Bookmarket Jarak Teks, Menunggu Tahap Teratas, Penunjuk Memuatkan AMP Baru Apr 17, 2025 am 11:26 AM

Pada minggu ini, roundup, sebuah bookmarklet yang berguna untuk memeriksa tipografi, menggunakan menunggu untuk mengamuk dengan cara modul JavaScript mengimport satu sama lain, ditambah Facebook &#039; s

Pilihan untuk menganjurkan analisis berasaskan bukan JavaScript anda sendiri Pilihan untuk menganjurkan analisis berasaskan bukan JavaScript anda sendiri Apr 15, 2025 am 11:09 AM

Terdapat banyak platform analisis untuk membantu anda mengesan data pelawat dan penggunaan di laman web anda. Mungkin paling penting Google Analytics, yang digunakan secara meluas

See all articles